home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / program / freeli20.zip / 386lib1.asx < prev    next >
Text File  |  1996-07-01  |  96KB  |  3,222 lines

  1. ~~~C_START
  2. Ideal
  3.  
  4. Extrn       main:near
  5. Public      startup, exit
  6. Public      TopByte, AtExitCnt
  7.  
  8. Model Tiny
  9. CodeSeg
  10. P386
  11.  
  12. ;****************** startup() -- Start program
  13.  
  14. Proc        startup
  15.  
  16.             pushf                   ;Check for 386+
  17.             pushf
  18.             pop ax
  19.             xor ax,7000h
  20.             push ax
  21.             popf
  22.             pushf
  23.             pop bx
  24.             popf
  25.             cmp ax,bx
  26.             jne p0_badcpu
  27.  
  28.             mov ax,3001h            ;Check for DOS 4.0
  29.             int 21h
  30.             cmp al,4
  31.             jb p0_baddos
  32.  
  33.             mov ah,4Ah              ;Modify memory allocation
  34.             mov bx,1000h            ;Keep first 64K
  35.             int 21h                 ;DOS call
  36.  
  37.             mov sp,0FF00h           ;Shift stack down 256 bytes
  38.  
  39.             mov ax,2523h            ;Set null Ctrl-C handler
  40.             mov dx,offset IntRet    ;so that Ctrl-C can't
  41.             int 21h                 ;abort the program
  42.  
  43.             mov ax,3500h            ;Get current Int 0 handler
  44.             int 21h                 ; (divide by zero)
  45.  
  46.             mov [word OldInt0],bx   ;Save handler
  47.             mov [word OldInt0+2],es
  48.  
  49.             push cs                 ;Restore ES
  50.             pop es
  51.  
  52.             mov ax,2500h            ;Set the divide by zero
  53.             mov dx,offset DivZero   ;handler: now it just
  54.             int 21h                 ;ignores the error
  55.  
  56.             mov ax,0FB00h           ;Initialize dynamic memory
  57.             sub ax,offset TopByte   ;leaving 768 bytes for the
  58.             mov [word TopByte],ax   ;stack (which is at 0FF00h)
  59.             mov [byte TopByte+2],2  ;Initial block is free, last
  60.  
  61.             mov di,sp               ;Parse arguments
  62.             call ParseArgs
  63.  
  64.             call main               ;Call main function
  65.  
  66.             push ax                 ;Terminate with return code
  67.             call exit
  68.  
  69. p0_baddos:  push offset BadDosStr   ;'Bad Dos' message
  70.             jmp p0_error
  71.  
  72. p0_badcpu:  push offset BadCPUStr   ;'Bad CPU' message
  73.  
  74. p0_error:   mov dx,offset BadStr    ;Print first part
  75.             mov ah,9
  76.             int 21h
  77.             pop dx                  ;Print second part
  78.             int 21h
  79.             mov ax,4CFFh            ;Return with error 255
  80.             int 21h
  81.  
  82. EndP        startup
  83.  
  84. ;****************** DivZero -- Divide by zero handler
  85.  
  86. Proc        DivZero
  87.  
  88.             push bp                 ;Set up stack frame
  89.             mov bp,sp
  90.             pusha                   ;Save all registers
  91.             push ds
  92.  
  93.             xor cx,cx               ;CX = displacement
  94.  
  95.             mov ds,[bp+4]           ;DS:BX = DIV instruction
  96.             mov bx,[bp+2]
  97.             cmp [byte bx],66h       ;Skip past opsize, if any
  98.             jne $+4
  99.             inc bx
  100.             inc cx
  101.             mov al,[bx+1]           ;AL = AH = ModRM byte
  102.             mov ah,al
  103.  
  104.             and al,0C0h             ;Mask off mode bits
  105.             cmp al,0C0h             ;Mode = 11 (no disp)?
  106.             je DZ_dis0
  107.             cmp al,040h             ;Mode = 01 (1 byte disp)?
  108.             je DZ_dis1
  109.             cmp al,080h             ;Mode = 10 (2 byte disp)?
  110.             je DZ_dis2
  111.             cmp ah,36h              ;Mode = 00.  No disp except
  112.             jne DZ_dis0             ;if R/M = 110 (2 byte disp).
  113.  
  114. DZ_dis2:    inc cx                  ;2 byte displacement
  115. DZ_dis1:    inc cx                  ;1 byte displacement
  116. DZ_dis0:    inc cx                  ;Instruction is two bytes
  117.             inc cx
  118.             add [bp+2],cx           ;Skip past instruction
  119.  
  120. DZ_done:    pop ds                  ;Restore registers
  121.             popa
  122.             pop bp                  ;Delete stack frame
  123. IntRet:     iret                    ;Interrupt return
  124.  
  125. EndP        DivZero
  126.  
  127. ;****************** Internal data
  128.  
  129. OldInt0:                            ;Old divide-by-zero handler
  130. BadStr      db 'Need at least $'    ;OK to overwrite strings
  131. BadCPUStr   db 'an 80386 CPU',13,10,'$'
  132. BadDosStr   db 'DOS 4.0',13,10,'$'
  133.  
  134. AtExitCnt   dw 0                    ;Exit function count
  135. AtExitTblO  equ 0FF60h              ;Exit function table offset
  136.  
  137. ;****************** exit() -- Terminate program
  138. ;void exit(int retval);
  139.  
  140. Proc        exit
  141.  
  142.             mov ax,2500h            ;Reset the default divide
  143.             mov dx,[word OldInt0]   ;by zero handler
  144.             mov ds,[word OldInt0+2]
  145.             int 21h
  146.  
  147.             push cs                 ;Restore DS
  148.             pop ds
  149.  
  150.             mov cx,[AtExitCnt]      ;CX = atexit count
  151.             jcxz p1_done            ;No exit functions?
  152.             mov si,AtExitTblO       ;SI = atexit table
  153.  
  154. p1_loop:    lodsw                   ;Get function
  155.             call ax                 ;Call function
  156.             loop p1_loop            ;Loop back
  157.  
  158. p1_done:    pop ax ax               ;Pop arg into AX
  159.             mov ah,4Ch              ;Terminate program
  160.             int 21h                 ;DOS call
  161.  
  162. EndP        exit
  163.  
  164. ;**************************** ParseArgs() -- internal: Parse arguments
  165.  
  166. Proc        ParseArgs
  167.             ;Supply DI = 256-byte buffer, CS = DS = ES
  168.             ;Returns CX = number of arguments
  169.             ;the buffer will contain a list of
  170.             ;near offsets to AsciiZ strings
  171.             ;(and the strings themselves)
  172.  
  173.             push es                 ;Save registers
  174.             pusha
  175.  
  176.             mov bx,di               ;BX = buffer
  177.             mov cl,[80h]            ;CX = length of command line
  178.             xor ch,ch               ;which is stored at 80h
  179.  
  180.             push cx                 ;Save CX
  181.             mov si,81h              ;SI = command line
  182.             add di,80h              ;DI = second half of buffer
  183.             push di                 ;Save DI
  184.             rep movsb               ;Move command line out of DTA
  185.             xor al,al               ;Replace the CR at the end
  186.             stosb                   ;with a null
  187.             pop di cx               ;Restore DI, length in CX
  188.             inc cx                  ;Make length include last null
  189.             xor dx,dx               ;Zero argument counter
  190.             mov al,' '              ;AL = space
  191.  
  192. p3_loop:    repe scasb              ;Search for a non-space
  193.             dec di
  194.             inc cx
  195.             cmp [byte di],0         ;Is it a null?
  196.             je p3_done
  197.             mov [bx],di             ;Store offset in list
  198.             inc bx                  ;Advance pointers
  199.             inc bx
  200.             inc dx
  201.             repne scasb             ;Search for a space
  202.             mov [byte di-1],0       ;Replace it by a null
  203.             jmp p3_loop             ;Loop back
  204.  
  205. p3_done:    mov es,dx               ;Tricky -- put count in ES
  206.             popa                    ;Restore general registers
  207.             mov cx,es               ;Count in CX
  208.             pop es                  ;Restore ES
  209.             ret                     ;Return
  210.  
  211. EndP        ParseArgs
  212.  
  213. UDataSeg                            ;Uninit. data seg: dummy
  214.  
  215. Label       TopByte                 ;Top byte of code (start of heap)
  216.  
  217. End
  218.  
  219. ~~~C_ATEXIT
  220. Ideal
  221.  
  222. Extrn       AtExitCnt:word
  223. Public      atexit
  224.  
  225. Model Tiny
  226. CodeSeg
  227. P386
  228.  
  229. AtExitTblO  equ 0FF60h              ;Exit function table offset
  230.  
  231. ;****************** atexit() -- Add exit function
  232. ;int atexit(void *func);
  233.  
  234. func        equ bp+4
  235.  
  236. Proc        atexit
  237.  
  238.             push bp                 ;Set up stack frame
  239.             mov bp,sp
  240.             push bx                 ;Save BX
  241.  
  242.             cmp [word AtExitCnt],16 ;16 functions max
  243.             jae p2_error
  244.  
  245.             mov bx,[AtExitCnt]      ;BX = offset
  246.             add bx,bx
  247.             mov ax,[func]           ;AX = function
  248.             mov [AtExitTblO+bx],ax  ;Add function to table
  249.             inc [word AtExitCnt]    ;Increment count
  250.  
  251. p2_done:    pop bx                  ;Restore BX
  252.             pop bp                  ;Delete stack frame
  253.             ret 2                   ;Return
  254.  
  255. p2_error:   xor ax,ax               ;Return 0: failure
  256.             jmp p2_done
  257.  
  258. EndP        atexit
  259.  
  260. End
  261.  
  262. ~~~C_PUTCHR
  263. Ideal
  264.  
  265. Public      PUT_CHAR
  266.  
  267. Model Tiny
  268. CodeSeg
  269. P386
  270.  
  271. ;****************** PUT_CHAR -- Like Int 29h but with redirection.
  272. ;                               Takes AL = char.
  273.  
  274. Proc        PUT_CHAR
  275.  
  276.             pusha                   ;Save registers
  277.             xchg dx,ax              ;STDOUT output, DL = char
  278.             mov ah,2
  279.             int 21h                 ;DOS call
  280.             popa                    ;Restore registers
  281.             ret                     ;Return
  282.  
  283. EndP        PUT_CHAR
  284.  
  285. End
  286.  
  287. ~~~C_FILES
  288. Ideal
  289.  
  290. Public      fopen,fclose,fsetbuf
  291.  
  292. Model Tiny
  293. CodeSeg
  294. P386
  295.  
  296. ;****************** File Structure . . .
  297.  
  298. ;                   Offset  Size    Description
  299.  
  300. ;                     0     Word    File handle
  301. ;                     2     Word    File mode
  302. ;                     4     Dword   Buffer position in file
  303. ;                     8     Word    Buffer pointer position
  304. ;                     10    Word    Number of bytes in buffer
  305. ;                     12    Word    Size of buffer (N)
  306. ;                     14    Word    Signature 'FI'
  307. ;                     16    N bytes File buffer
  308.  
  309. BUF_SIZ     dw 1024                 ;Buffer size (default 1K)
  310.  
  311. F_MODES     db 00h,01h              ;0 = open for read
  312.             db 02h,11h              ;1 = open/create for read/write
  313.             db 02h,01h              ;2 = open for read/write
  314.             db 02h,12h              ;3 = create/truncate for read/write
  315.             db 02h,10h              ;4 = create for read/write
  316.             db 6 dup(0)             ;Fail for 5, 6, 7
  317.  
  318. ;****************** fopen() -- Open a buffered file
  319. ;int fopen(char *fname, int mode);
  320.  
  321. fname       = bp+6
  322. mode        = bp+4
  323.  
  324. Proc        fopen
  325.  
  326.             push bp                 ;Set up stack frame
  327.             mov bp,sp
  328.             push ds si bx cx dx     ;Save registers
  329.  
  330.             mov bx,[mode]           ;BX = mode
  331.             and bx,7                ;Mode mod 8
  332.             add bx,bx
  333.             movzx dx,[F_MODES+bx+1] ;BX:DX = DOS mode
  334.             movzx bx,[F_MODES+bx]
  335.  
  336.             mov ax,6C00h            ;Extended open file
  337.             xor cx,cx               ;Normal attribute
  338.             mov si,[fname]          ;SI = name
  339.             int 21h                 ;DOS call
  340.             jc p1_err1              ;Check for errors
  341.  
  342.             xchg dx,ax              ;DX = handle
  343.  
  344.             mov ah,48h              ;Allocate memory
  345.             mov bx,[BUF_SIZ]        ;BX = num. of paras
  346.             shr bx,4                ; = (BUF_SIZ / 16) + 1
  347.             inc bx
  348.             int 21h                 ;DOS call
  349.             jc p1_err2              ;Check for errors
  350.  
  351.             mov ds,ax               ;DS = segment
  352.             mov [word 0],dx         ;[word 0] = handle
  353.             mov cx,[mode]
  354.             mov [word 2],cx         ;[word 2] = mode
  355.             xor bx,bx
  356.             mov [word 4],bx         ;[dword 4] = buffer position
  357.             mov [word 6],bx
  358.             mov [word 8],bx         ;[word 8] = buffer pointer
  359.             mov bx,[cs:BUF_SIZ]
  360.             mov [word 12],bx        ;[word 12] = buffer size
  361.             mov [word 14],'FI'      ;[word 14] = 'FI': signature
  362.  
  363.             mov bx,dx               ;BX = handle
  364.             mov ah,3Fh              ;Read file
  365.             mov cx,[cs:BUF_SIZ]     ;BUF_SIZ bytes
  366.             mov dx,16               ;Buffer offset
  367.             int 21h                 ;DOS call
  368.  
  369.             mov [word 10],ax        ;Set byte count
  370.  
  371.             mov ax,ds               ;AX = segment
  372.  
  373. p1_done:    pop dx cx bx si ds      ;Restore registers
  374.             pop bp                  ;Delete stack frame
  375.             ret 4                   ;Return
  376.  
  377. p1_err2:    mov ah,3Eh              ;Out of memory, close file
  378.             mov bx,dx               ;BX = handle
  379.             int 21h                 ;DOS call
  380.  
  381. p1_err1:    xor ax,ax               ;Error, return 0
  382.             jmp p1_done
  383.  
  384. EndP        fopen
  385.  
  386. ;****************** fclose() -- Close a buffered file
  387. ;void fclose(int fptr);
  388.  
  389. fptr        = bp+4
  390.  
  391. Proc        fclose
  392.  
  393.             push bp                 ;Set up stack frame
  394.             mov bp,sp
  395.             push ds es              ;Save registers
  396.             pusha
  397.  
  398.             mov ds,[fptr]           ;DS = seg of file
  399.             cmp [word 14],'FI'      ;Check for signature
  400.             jne p2_done
  401.  
  402.             mov bx,[word 0]         ;BX = handle
  403.  
  404.             cmp [byte 2],0          ;Read only, can't write buffer
  405.             je p2_skip
  406.  
  407.             mov ax,4200h            ;Move file ptr
  408.             mov cx,[word 6]         ;CX:DX = buffer pos
  409.             mov dx,[word 4]
  410.             int 21h                 ;DOS call
  411.  
  412.             mov ah,40h              ;Write file
  413.             mov cx,[word 10]        ;CX = bytes
  414.             mov dx,16               ;Buffer offset
  415.             int 21h                 ;DOS call
  416.  
  417. p2_skip:    mov ah,3Eh              ;Close file
  418.             int 21h                 ;DOS call
  419.  
  420.             mov ah,49h              ;Free memory
  421.             push ds                 ;ES = segment
  422.             pop es
  423.             int 21h                 ;DOS call
  424.  
  425. p2_done:    popa                    ;Restore registers
  426.             pop es ds
  427.             pop bp                  ;Delete stack frame
  428.             ret 2                   ;Return
  429.  
  430. EndP        fclose
  431.  
  432. ;****************** fsetbuf() -- Set buffer size (for future use)
  433. ;int fsetbuf(int bsize);
  434.  
  435. bsize       = bp+4
  436.  
  437. Proc        fsetbuf
  438.  
  439.             push bp                 ;Set up stack frame
  440.             mov bp,sp
  441.  
  442.             mov ax,[bsize]          ;AX = size
  443.             and ax,7FF0h            ;Put it in range
  444.             cmp ax,128
  445.             jb $+5
  446.             mov ax,128
  447.             mov [BUF_SIZ],ax        ;Set buffer size
  448.  
  449.             pop bp                  ;Delete stack frame
  450.             ret 2                   ;Return
  451.  
  452. EndP        fsetbuf
  453.  
  454. End
  455.  
  456. ~~~C_FPUTC
  457. Ideal
  458.  
  459. Public      fputc
  460.  
  461. Model Tiny
  462. CodeSeg
  463. P386
  464.  
  465. ;****************** fputc() -- Put char to buffered file
  466. ;int fputc(int fptr, int chr);
  467.  
  468. fptr        = bp+6
  469. chr         = bp+4
  470.  
  471. Proc        fputc
  472.  
  473.             push bp                 ;Set up stack frame
  474.             mov bp,sp
  475.             push ds si bx cx dx     ;Save registers
  476.  
  477.             mov ds,[fptr]           ;DS = seg of file
  478.             cmp [word 14],'FI'      ;Check for signature
  479.             jne p1_error
  480.  
  481.             mov bx,[word 0]         ;BX = handle
  482.  
  483.             cmp [word 2],0          ;Read only, can't put char
  484.             je p1_error
  485.  
  486.             mov si,[word 8]         ;SI = pointer pos
  487.             cmp si,[word 12]        ;Filled buffer?
  488.             jb p1_write             ;Jump if not
  489.  
  490.             mov ax,4200h            ;Move file ptr
  491.             mov cx,[word 6]         ;CX:DX = buffer pos
  492.             mov dx,[word 4]
  493.             int 21h                 ;DOS call
  494.  
  495.             mov ah,40h              ;Write file
  496.             mov cx,[word 12]        ;CX = bytes
  497.             mov dx,16               ;Buffer offset
  498.             int 21h                 ;DOS call
  499.  
  500.             mov ah,3Fh              ;Read file, same data...
  501.             int 21h                 ;DOS call
  502.             mov [word 10],ax        ;Set byte count
  503.  
  504.             xor si,si
  505.             add [word 4],cx         ;Advance buffer position
  506.             adc [word 6],si
  507.             mov [word 8],si         ;Pointer pos = 0
  508.  
  509. p1_write:   mov al,[chr]            ;AX = char
  510.             xor ah,ah
  511.             mov [16+si],al          ;Put char in buffer
  512.             inc si                  ;Advance pointer
  513.             mov [word 8],si
  514.             cmp si,[word 10]        ;Hit last byte?
  515.             jna p1_done
  516.  
  517.             inc [word 10]           ;Advance byte count
  518.  
  519. p1_done:    pop dx cx bx si ds      ;Restore registers
  520.             pop bp                  ;Delete stack frame
  521.             ret 4                   ;Return
  522.  
  523. p1_error:   mov ax,-1               ;Error, return EOF
  524.             jmp p1_done
  525.  
  526. EndP        fputc
  527.  
  528. End
  529.  
  530. ~~~C_FGETC
  531. Ideal
  532.  
  533. Public      fgetc
  534.  
  535. Model Tiny
  536. CodeSeg
  537. P386
  538.  
  539. ;****************** fgetc() -- Get char from buffered file
  540. ;int fgetc(int fptr);
  541.  
  542. fptr        = bp+4
  543.  
  544. Proc        fgetc
  545.  
  546.             push bp                 ;Set up stack frame
  547.             mov bp,sp
  548.             push ds si bx cx dx     ;Save registers
  549.  
  550.             mov ds,[fptr]           ;DS = seg of file
  551.             cmp [word 14],'FI'      ;Check for signature
  552.             jne p1_error
  553.  
  554.             mov bx,[word 0]         ;BX = handle
  555.  
  556.             mov si,[word 8]         ;SI = pointer pos
  557.             mov cx,[word 12]        ;CX = buffer size
  558.             cmp si,cx               ;End of buffer?
  559.             jb p1_read              ;Jump if not
  560.  
  561.             xor si,si
  562.             add [word 4],cx         ;Advance buffer position
  563.             adc [word 6],si
  564.             mov [word 2],si         ;Pointer pos = 0
  565.  
  566.             mov ax,4200h            ;Move file ptr
  567.             mov cx,[word 6]         ;CX:DX = buffer pos
  568.             mov dx,[word 4]
  569.             int 21h                 ;DOS call
  570.  
  571.             mov ah,3Fh              ;Read file
  572.             mov cx,[word 12]        ;CX = bytes
  573.             mov dx,16               ;Buffer offset
  574.             int 21h                 ;DOS call
  575.             mov [word 10],ax        ;Set byte count
  576.  
  577. p1_read:    cmp si,[word 10]        ;Hit last byte?
  578.             jae p1_error
  579.  
  580.             mov al,[16+si]          ;Get char from buffer
  581.             xor ah,ah
  582.             inc si                  ;Advance pointer
  583.             mov [word 8],si
  584.  
  585. p1_done:    pop dx cx bx si ds      ;Restore registers
  586.             pop bp                  ;Delete stack frame
  587.             ret 2                   ;Return
  588.  
  589. p1_error:   mov ax,-1               ;Error, return EOF
  590.             jmp p1_done
  591.  
  592. EndP        fgetc
  593.  
  594. End
  595.  
  596. ~~~C_FSEEK
  597. Ideal
  598.  
  599. Public      fseek,ftell
  600.  
  601. Model Tiny
  602. CodeSeg
  603. P386
  604.  
  605. ;****************** fseek() -- Seek to position in buffered file
  606. ;int fseek(int fptr, long pos, int cmd);
  607.  
  608. fptr        = bp+10
  609. pos         = bp+6
  610. cmd         = bp+4
  611.  
  612. Proc        fseek
  613.  
  614.             push bp                 ;Set up stack frame
  615.             mov bp,sp
  616.             push ds bx cx dx        ;Save registers
  617.  
  618.             mov ds,[fptr]           ;DS = seg of file
  619.             cmp [word 14],'FI'      ;Check for signature
  620.             jne p1_error
  621.  
  622.             mov bx,[word 0]         ;BX = handle
  623.  
  624.             cmp [word 2],0          ;Read only, can't write buffer
  625.             je p1_seek
  626.  
  627.             mov ax,4200h            ;Move file ptr
  628.             mov cx,[word 6]         ;CX:DX = buffer pos
  629.             mov dx,[word 4]
  630.             int 21h                 ;DOS call
  631.  
  632.             mov ah,40h              ;Write file
  633.             mov cx,[word 10]        ;CX = bytes
  634.             mov dx,16               ;Buffer offset
  635.             int 21h                 ;DOS call
  636.  
  637. p1_seek:    mov ax,4200h            ;Move file ptr
  638.             mov cx,[word 6]         ;CX:DX = current pos
  639.             mov dx,[word 4]         ; = buffer pos + pointer
  640.             add dx,[word 8]
  641.             adc cx,0
  642.             int 21h                 ;DOS call
  643.  
  644.             mov ah,42h              ;Move file ptr
  645.             mov al,[cmd]            ;AL = command
  646.             mov cx,[pos+2]          ;CX:DX = new pos
  647.             mov dx,[pos]
  648.             int 21h                 ;DOS call
  649.  
  650.             mov [word 6],dx         ;Save position
  651.             mov [word 4],ax
  652.  
  653.             mov ah,3Fh              ;Read file
  654.             mov cx,[word 12]        ;CX = bytes
  655.             mov dx,16               ;Buffer offset
  656.             int 21h                 ;DOS call
  657.  
  658.             mov [word 10],ax        ;Set byte count
  659.             mov [word 8],0          ;Pointer = 0
  660.             mov ax,1                ;return 1: success
  661.  
  662. p1_done:    pop dx cx bx ds         ;Restore registers
  663.             pop bp                  ;Delete stack frame
  664.             ret 8                   ;Return
  665.  
  666. p1_error:   xor ax,ax               ;Error, return 0
  667.             jmp p1_done
  668.  
  669. EndP        fseek
  670.  
  671. ;****************** ftell() -- Return pointer in buffered file
  672. ;long ftell(int fptr);
  673.  
  674. fptr        = bp+4
  675.  
  676. Proc        ftell
  677.  
  678.             push bp                 ;Set up stack frame
  679.             mov bp,sp
  680.             push ds                 ;Save registers
  681.  
  682.             mov ds,[fptr]           ;DS = seg of file
  683.             cmp [word 14],'FI'      ;Check for signature
  684.             jne p2_error
  685.  
  686.             mov dx,[word 6]         ;DX:AX = current pos
  687.             mov ax,[word 4]         ; = buffer pos + pointer
  688.             add ax,[word 8]
  689.             adc dx,0
  690.  
  691. p2_done:    pop ds                  ;Restore registers
  692.             pop bp                  ;Delete stack frame
  693.             ret 2                   ;Return
  694.  
  695. p2_error:   xor ax,ax               ;Error, return 0
  696.             xor dx,dx
  697.             jmp p2_done
  698.  
  699. EndP        ftell
  700.  
  701. End
  702.  
  703. ~~~C_FREAD
  704. Ideal
  705.  
  706. Extrn       fgetc:near
  707. Public      fread
  708.  
  709. Model Tiny
  710. CodeSeg
  711. P386
  712.  
  713. ;****************** fread() -- Read block from buffered file
  714. ;int fread(int fptr, int nbytes, void *buf);
  715.  
  716. fptr        = bp+8
  717. nbytes      = bp+6
  718. buf         = bp+4
  719.  
  720. Proc        fread
  721.  
  722.             push bp                 ;Set up stack frame
  723.             mov bp,sp
  724.             push bx cx di           ;Save registers
  725.  
  726.             mov bx,[fptr]           ;BX = file ptr
  727.             mov cx,[nbytes]         ;CX = num. of bytes
  728.             mov di,[buf]            ;DI = buffer ptr
  729.             jcxz p1_done            ;Zero bytes, do nothing
  730.  
  731. p1_loop:    push bx                 ;Get char
  732.             call fgetc
  733.             test ax,ax              ;Check for errors
  734.             jl p1_done
  735.             mov [di],al             ;Store byte
  736.             inc di
  737.             loop p1_loop            ;Loop back
  738.  
  739. p1_done:    sub di,[buf]            ;AX = byte count
  740.             xchg ax,di
  741.  
  742.             pop di cx bx            ;Restore registers
  743.             pop bp                  ;Delete stack frame
  744.             ret 6                   ;Return
  745.  
  746. EndP        fread
  747.  
  748. End
  749.  
  750. ~~~C_FWRITE
  751. Ideal
  752.  
  753. Extrn       fputc:near
  754. Public      fwrite
  755.  
  756. Model Tiny
  757. CodeSeg
  758. P386
  759.  
  760. ;****************** fwrite() -- Write block to buffered file
  761. ;int fwrite(int fptr, int nbytes, void *buf);
  762.  
  763. fptr        = bp+8
  764. nbytes      = bp+6
  765. buf         = bp+4
  766.  
  767. Proc        fwrite
  768.  
  769.             push bp                 ;Set up stack frame
  770.             mov bp,sp
  771.             push bx cx si           ;Save registers
  772.  
  773.             mov bx,[fptr]           ;BX = file ptr
  774.             mov cx,[nbytes]         ;CX = num. of bytes
  775.             mov si,[buf]            ;SI = buffer ptr
  776.             mov ax,1                ;Fixup for zero check
  777.             jcxz p1_done            ;Zero bytes, do nothing
  778.  
  779. p1_loop:    lodsb                   ;Load byte
  780.             push bx ax              ;Write char
  781.             call fputc
  782.             test ax,ax              ;Check for errors
  783.             jl p1_done
  784.             loop p1_loop            ;Loop back
  785.  
  786. p1_done:    sub si,[buf]            ;AX = byte count
  787.             dec ax                  ;Subtract 1 if error
  788.             sbb si,0
  789.             xchg ax,si
  790.  
  791.             pop si cx bx            ;Restore registers
  792.             pop bp                  ;Delete stack frame
  793.             ret 6                   ;Return
  794.  
  795. EndP        fwrite
  796.  
  797. End
  798.  
  799. ~~~C_FTRUNC
  800. Ideal
  801.  
  802. Public      ftrunc
  803.  
  804. Model Tiny
  805. CodeSeg
  806. P386
  807.  
  808. ;****************** ftrunc() -- Truncate buffered file at current position
  809. ;int ftrunc(int fptr);
  810.  
  811. fptr        = bp+4
  812.  
  813. Proc        ftrunc
  814.  
  815.             push bp                 ;Set up stack frame
  816.             mov bp,sp
  817.             push ds bx cx dx        ;Save registers
  818.  
  819.             mov ds,[fptr]           ;DS = seg of file
  820.             cmp [word 14],'FI'      ;Check for signature
  821.             jne p1_error
  822.  
  823.             cmp [word 2],0          ;Read only, can't truncate
  824.             je p1_error
  825.  
  826.             mov bx,[word 0]         ;BX = handle
  827.  
  828.             mov ax,4200h            ;Move file ptr
  829.             mov cx,[word 6]         ;CX:DX = current pos
  830.             mov dx,[word 4]         ; = buffer pos + pointer
  831.             add dx,[word 8]
  832.             adc cx,0
  833.             int 21h                 ;DOS call
  834.  
  835.             mov ah,40h              ;Write 0 bytes to file
  836.             xor cx,cx               ;this truncates the file
  837.             int 21h
  838.  
  839.             mov ax,[word 8]         ;Now, byte count = pointer + 1
  840.             inc ax
  841.             mov [word 10],ax
  842.             mov ax,1                ;return 1: success
  843.  
  844. p1_done:    pop dx cx bx ds         ;Restore registers
  845.             pop bp                  ;Delete stack frame
  846.             ret 2                   ;Return
  847.  
  848. p1_error:   xor ax,ax               ;Error, return 0
  849.             jmp p1_done
  850.  
  851. EndP        ftrunc
  852.  
  853. End
  854.  
  855. ~~~C_DELMOV
  856. Ideal
  857.  
  858. Public      fdel,fmove
  859.  
  860. Model Tiny
  861. CodeSeg
  862. P386
  863.  
  864. ;****************** fdel() -- Delete a file
  865. ;int fdel(char *strp);
  866.  
  867. strp        equ bp+4
  868.  
  869. Proc        fdel
  870.  
  871.             push bp                 ;Set up stack frame
  872.             mov bp,sp
  873.             push dx                 ;Save DX
  874.  
  875.             mov ah,41h              ;Delete file
  876.             mov dx,[strp]           ;DX = string pointer
  877.             int 21h                 ;DOS call
  878.  
  879.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  880.             cbw                     ;AX = 1 if ok, 0 if error
  881.             inc ax
  882.  
  883.             pop dx                  ;Restore DX
  884.             pop bp                  ;Delete stack frame
  885.             ret 2                   ;Return
  886.  
  887. EndP        fdel
  888.  
  889. ;****************** fmove() -- Move and/or rename a file
  890. ;int fmove(char *str1, char *str2);
  891.  
  892. str1        equ bp+6
  893. str2        equ bp+4
  894.  
  895. Proc        fmove
  896.  
  897.             push bp                 ;Set up stack frame
  898.             mov bp,sp
  899.             push es dx di           ;Save registers
  900.  
  901.             mov ah,56h              ;Move file
  902.             mov dx,[str1]           ;DX = old name
  903.             push ds                 ;ES = DS
  904.             pop es
  905.             mov di,[str2]           ;ES:DI = new name
  906.             int 21h                 ;DOS call
  907.  
  908.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  909.             cbw                     ;AX = 1 if ok, 0 if error
  910.             inc ax
  911.  
  912.             pop di dx es            ;Restore registers
  913.             pop bp                  ;Delete stack frame
  914.             ret 4                   ;Return
  915.  
  916. EndP        fmove
  917.  
  918. End
  919.  
  920. ~~~C_DIRECT
  921. Ideal
  922.  
  923. Public      getdir,setdir,mkdir,rmdir
  924.  
  925. Model Tiny
  926. CodeSeg
  927. P386
  928.  
  929. ;****************** getdir() -- Get current directory
  930. ;void getdir(char *strp);
  931.  
  932. strp        equ bp+4
  933.  
  934. Proc        getdir
  935.  
  936.             push bp                 ;Set up stack frame
  937.             mov bp,sp
  938.             pusha                   ;Save registers
  939.  
  940.             mov ah,19h              ;Get current drive
  941.             int 21h                 ;DOS call
  942.  
  943.             mov dl,al               ;DL = drive
  944.             mov ah,47h              ;Get current directory
  945.             mov si,[strp]           ;SI = string pointer
  946.             mov [byte si],'\'       ;Add leading slash
  947.             inc si
  948.             int 21h                 ;DOS call
  949.  
  950.             popa                    ;Restore registers
  951.             pop bp                  ;Delete stack frame
  952.             ret 2                   ;Return
  953.  
  954. EndP        getdir
  955.  
  956. ;****************** DIRcall -- Internal: used by setdir,mkdir,rmdir
  957. ;void DIRcall(void);
  958.  
  959. strp        equ bp+4
  960.  
  961. Proc        DIRcall
  962.  
  963.             push dx                 ;Save DX
  964.             mov dx,[strp]           ;DX = string pointer
  965.             int 21h                 ;DOS call
  966.  
  967.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  968.             cbw                     ;AX = 1 if ok, 0 if error
  969.             inc ax
  970.  
  971.             pop dx                  ;Restore DX
  972.             ret                     ;Return
  973.  
  974. EndP        DIRcall
  975.  
  976. ;****************** setdir() -- Set current directory
  977. ;int setdir(char *strp);
  978.  
  979. strp        equ bp+4
  980.  
  981. Proc        setdir
  982.  
  983.             push bp                 ;Set up stack frame
  984.             mov bp,sp
  985.  
  986.             mov ah,3Bh              ;Set current directory
  987.             call DIRcall            ;Directory call
  988.  
  989.             pop bp                  ;Delete stack frame
  990.             ret 2                   ;Return
  991.  
  992. EndP        setdir
  993.  
  994. ;****************** mkdir() -- Create a directory
  995. ;int mkdir(char *strp);
  996.  
  997. strp        equ bp+4
  998.  
  999. Proc        mkdir
  1000.  
  1001.             push bp                 ;Set up stack frame
  1002.             mov bp,sp
  1003.  
  1004.             mov ah,39h              ;Create directory
  1005.             call DIRcall            ;Directory call
  1006.  
  1007.             pop bp                  ;Delete stack frame
  1008.             ret 2                   ;Return
  1009.  
  1010. EndP        mkdir
  1011.  
  1012. ;****************** rmdir() -- Remove a directory
  1013. ;int rmdir(char *strp);
  1014.  
  1015. strp        equ bp+4
  1016.  
  1017. Proc        rmdir
  1018.  
  1019.             push bp                 ;Set up stack frame
  1020.             mov bp,sp
  1021.  
  1022.             mov ah,3Ah              ;Remove directory
  1023.             call DIRcall            ;Directory call
  1024.  
  1025.             pop bp                  ;Delete stack frame
  1026.             ret 2                   ;Return
  1027.  
  1028. EndP        rmdir
  1029.  
  1030. End
  1031.  
  1032. ~~~C_DRIVE
  1033. Ideal
  1034.  
  1035. Public      getdrive,setdrive
  1036.  
  1037. Model Tiny
  1038. CodeSeg
  1039. P386
  1040.  
  1041. ;****************** getdrive() -- Get current drive
  1042. ;int getdrive(void);
  1043.  
  1044. Proc        getdrive
  1045.  
  1046.             mov ah,19h              ;Get current drive
  1047.             int 21h
  1048.             xor ah,ah               ;Zero AH
  1049.             ret                     ;Return
  1050.  
  1051. EndP        getdrive
  1052.  
  1053. ;****************** setdrive() -- set current drive
  1054. ;void setdrive(int drnum);
  1055.  
  1056. drnum       equ bp+4
  1057.  
  1058. Proc        setdrive
  1059.  
  1060.             push bp                 ;Set up stack frame
  1061.             mov bp,sp
  1062.             pusha                   ;Save registers
  1063.  
  1064.             mov ah,0Eh              ;Set current drive
  1065.             mov dl,[drnum]          ;DL = drive number
  1066.             int 21h
  1067.  
  1068.             popa                    ;Restore registers
  1069.             pop bp                  ;Delete stack frame
  1070.             ret 2                   ;Return
  1071.  
  1072. EndP        setdrive
  1073.  
  1074. End
  1075.  
  1076. ~~~C_DFREE
  1077. Ideal
  1078.  
  1079. Public      getdfree
  1080.  
  1081. Model Tiny
  1082. CodeSeg
  1083. P386
  1084.  
  1085. ;****************** getdfree() -- Return amount of free disk space
  1086. ;long getdfree(int drive);
  1087.  
  1088. drive       equ bp+4
  1089.  
  1090. Proc        getdfree
  1091.  
  1092.             push bp                 ;Set up stack frame
  1093.             mov bp,sp
  1094.             push bx cx              ;Save registers
  1095.  
  1096.             mov dl,[drive]          ;DL = drive
  1097.             mov ah,36h              ;Get free disk space
  1098.             int 21h
  1099.  
  1100.             cbw                     ;DX:AX = AX
  1101.             cmp ax,-1               ;Invalid, return -1
  1102.             je p1_done
  1103.  
  1104.             mul cx                  ;DX:AX = free disk space
  1105.             mul bx                  ; = bytes/sector * sectors/a-unit
  1106.                                     ; * free a-units (allocation units)
  1107.  
  1108. p1_done:    pop cx bx               ;Restore registers
  1109.             pop bp                  ;Delete stack frame
  1110.             ret                     ;Return
  1111.  
  1112. EndP        getdfree
  1113.  
  1114. End
  1115.  
  1116. ~~~C_EXEC
  1117. Ideal
  1118.  
  1119. Extrn       allocmem:near,freemem:near
  1120. Public      exec
  1121.  
  1122. Model Tiny
  1123. CodeSeg
  1124. P386
  1125.  
  1126. ;****************** exec() -- Execute program
  1127. ;int exec(char *prog, char *cmdline);
  1128.  
  1129. prog        equ bp+6
  1130. cmdline     equ bp+4
  1131.  
  1132. Proc        exec
  1133.  
  1134.             push bp                 ;Set up stack frame
  1135.             mov bp,sp
  1136.             push ds es              ;Save all registers
  1137.             pusha
  1138.  
  1139.             push 128                ;Allocate memory for
  1140.             call allocmem           ;the cmdline buffer
  1141.             test ax,ax              ;Out of memory?
  1142.             je p1_done
  1143.             xchg bx,ax              ;Pointer in BX
  1144.  
  1145.             mov si,[prog]           ;SI = program specification
  1146.  
  1147. p1_loop1:   lodsb                   ;Skip past initial spaces
  1148.             cmp al,' '
  1149.             je p1_loop1
  1150.             dec si
  1151.             push si                 ;Save prog string offset
  1152.  
  1153.             mov si,[cmdline]        ;SI = command line
  1154.             mov di,bx               ;DI = string buffer
  1155.             inc di
  1156.             mov cx,126              ;CX = 126
  1157.  
  1158. p1_loop3:   lodsb                   ;Copy the string and
  1159.             test al,al              ;count the chars
  1160.             je p1_cont
  1161.             stosb
  1162.             loop p1_loop3
  1163.  
  1164. p1_cont:    neg cx                  ;CX = char count
  1165.             add cx,126
  1166.             mov [bx],cl             ;Store count
  1167.             mov al,13               ;Store a CR
  1168.             stosb
  1169.  
  1170.             mov ax,[2Eh]            ;word 0 = environment
  1171.             mov [ParBlock],ax
  1172.             mov [ParBlock+2],bx     ;word 2 = command line
  1173.             mov [ParBlock+4],cs     ;word 4 = CS
  1174.             mov [ParBlock+6],5Ch    ;word 6 = 5Ch
  1175.             mov [ParBlock+8],cs     ;word 8 = CS
  1176.             mov [ParBlock+10],6Ch   ;word 10 = 6Ch
  1177.             mov [ParBlock+12],cs    ;word 12 = CS
  1178.  
  1179.             push bx                 ;Save memory pointer
  1180.  
  1181.             push ds                 ;ES:BX = parameter block
  1182.             pop es
  1183.             mov bx,offset ParBlock
  1184.             pop dx                  ;DX = program specification
  1185.             mov ax,4B00h            ;DOS EXEC function
  1186.  
  1187.             mov [StackBuf],sp       ;Save stack pointer
  1188.             mov [StackBuf+2],ss
  1189.  
  1190.             int 21h                 ;Execute program
  1191.  
  1192.             lss sp,[dword cs:StackBuf]  ;Restore stack pointer
  1193.  
  1194.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  1195.             cbw                     ;AX = 1 if ok, 0 if error
  1196.             inc ax
  1197.  
  1198.             call freemem            ;Free the memory (BX is still pushed)
  1199.  
  1200. p1_done:    mov es,ax               ;Save AX in ES
  1201.             popa                    ;Restore general registers
  1202.             mov ax,es               ;Restore AX
  1203.             pop es ds               ;Restore segment registers
  1204.             pop bp                  ;Delete stack frame
  1205.             ret 4                   ;Return
  1206.  
  1207. StackBuf    dw 0,0                  ;Save area for SS:SP
  1208.  
  1209. ParBlock    dw 7 dup(0)             ;EXEC parameter block
  1210.  
  1211. EndP        exec
  1212.  
  1213. End
  1214.  
  1215. ~~~C_BITIO
  1216. Ideal
  1217.  
  1218. Extrn       fopen:near,fclose:near,fgetc:near,fputc:near
  1219. Public      bfopen, bfclose, putbit, getbit
  1220. Public      putbits, getbits, putcode, getcode
  1221.  
  1222. Model Tiny
  1223. P386
  1224. CodeSeg
  1225.  
  1226. ;****************** Bit-File Structure . . .
  1227.  
  1228. ;                   Offset  Size    Description
  1229.  
  1230. ;                     0     Word    File handle
  1231. ;                     2     Word    File mode
  1232. ;                     4     Byte    Bit buffer
  1233. ;                     5     Byte    Bit mask
  1234.  
  1235. ;****************** bfopen() -- Open bit-file (returns bit handle)
  1236. ;                               Modes: 0 = read, 1 = write
  1237. ;int bfopen(char *fname, int mode);
  1238.  
  1239. fname       equ bp+6
  1240. mode        equ bp+4
  1241.  
  1242. Proc        bfopen
  1243.  
  1244.             push bp                 ;Set up stack frame
  1245.             mov bp,sp
  1246.             push ds bx cx dx        ;Save registers
  1247.  
  1248.             mov bx,[mode]           ;BX = mode
  1249.             and bx,1
  1250.             mov cx,bx               ;Save mode
  1251.             imul bx,3               ;Mode for fopen()
  1252.  
  1253.             push [word fname] bx    ;Open the file
  1254.             call fopen
  1255.             test ax,ax              ;Check for errors
  1256.             jz p1_err1
  1257.             xchg dx,ax              ;DX = file
  1258.  
  1259.             mov ah,48h              ;Allocate memory
  1260.             mov bx,1                ;16 bytes
  1261.             int 21h                 ;DOS call
  1262.             jc p1_err2              ;Check for errors
  1263.  
  1264.             mov ds,ax               ;DS = bit-file
  1265.             mov [0],dx              ;Set file handle...
  1266.             mov [2],cx              ;file mode...
  1267.             mov [word 4],8000h      ;buffer/mask...
  1268.  
  1269. p1_done:    pop dx cx bx ds         ;Restore registers
  1270.             pop bp                  ;Delete stack frame
  1271.             ret 4                   ;Return
  1272.  
  1273. p1_err2:    push dx                 ;Out of memory, close file
  1274.             call fclose
  1275.  
  1276. p1_err1:    xor ax,ax               ;Error, return 0
  1277.             jmp p1_done
  1278.  
  1279. EndP        bfopen
  1280.  
  1281. ;****************** bfclose() -- Close bit-file
  1282. ;void bfclose(int bfp);
  1283.  
  1284. bfp         equ bp+4
  1285.  
  1286. Proc        bfclose
  1287.  
  1288.             push bp                 ;Set up stack frame
  1289.             mov bp,sp
  1290.             pusha                   ;Save all registers
  1291.             push es
  1292.  
  1293.             mov es,[bfp]            ;ES = bit-file
  1294.  
  1295.             cmp [word es:2],1       ;Input file?
  1296.             jne p2_skip
  1297.             cmp [byte es:5],80h     ;Buffer empty?
  1298.             je p2_skip
  1299.  
  1300.             push [word es:0]        ;Flush buffer
  1301.             push [word es:4]
  1302.             call fputc
  1303.  
  1304. p2_skip:    push [word es:0]        ;Close file
  1305.             call fclose
  1306.             mov ah,49h              ;Free memory
  1307.             int 21h
  1308.  
  1309.             pop es                  ;Restore registers
  1310.             popa
  1311.             pop bp                  ;Delete stack frame
  1312.             ret 2                   ;Return
  1313.  
  1314. EndP        bfclose
  1315.  
  1316. ;****************** getbit() -- Get bit from bit-file
  1317. ;int getbit(int bfp);
  1318.  
  1319. bfp         equ bp+4
  1320.  
  1321. Proc        getbit
  1322.  
  1323.             push bp                 ;Set up stack frame
  1324.             mov bp,sp
  1325.             push es                 ;Save registers
  1326.  
  1327.             mov es,[bfp]            ;ES = bit-file
  1328.             cmp [word es:2],0       ;Output file, can't input
  1329.             jne p3_done
  1330.             cmp [byte es:5],80h     ;Buffer empty?
  1331.             jne p3_skip1
  1332.  
  1333.             push [word es:0]        ;Get char
  1334.             call fgetc
  1335.             mov [es:4],al           ;Save char
  1336.  
  1337. p3_skip1:   mov al,[es:4]           ;Get bit
  1338.             and al,[es:5]
  1339.             shr [byte es:5],1       ;Move to next bit
  1340.             jnz p3_skip2            ;Finished a byte?
  1341.             mov [byte es:5],80h     ;Set mask to 80h
  1342.  
  1343. p3_skip2:   test al,al              ;AX = 1 if nonzero,
  1344.             setnz al                ;or 0 if zero
  1345.             cbw
  1346.  
  1347. p3_done:    pop es                  ;Restore registers
  1348.             pop bp                  ;Delete stack frame
  1349.             ret 2                   ;Return
  1350.  
  1351. EndP        getbit
  1352.  
  1353. ;****************** putbit() -- Put bit to bit-file
  1354. ;void putbit(int bfp, int bit);
  1355.  
  1356. bfp         equ bp+6
  1357. bit         equ bp+4
  1358.  
  1359. Proc        putbit
  1360.  
  1361.             push bp                 ;Set up stack frame
  1362.             mov bp,sp
  1363.             pusha                   ;Save all registers
  1364.             push es
  1365.  
  1366.             mov es,[bfp]            ;ES = bit-file
  1367.             cmp [word es:2],1       ;Input file, can't output
  1368.             jne p4_done
  1369.  
  1370.             cmp [word bit],0        ;Check bit
  1371.             jz p4_skip
  1372.             mov al,[es:5]           ;Add bit to buffer
  1373.             or [es:4],al
  1374.  
  1375. p4_skip:    shr [byte es:5],1       ;Move to next bit
  1376.             jnz p4_done             ;Finished a byte?
  1377.  
  1378.             push [word es:0]        ;Put byte to file
  1379.             push [word es:4]
  1380.             call fputc
  1381.             mov [word es:4],8000h   ;Buf = 0, Mask = 80h
  1382.  
  1383. p4_done:    pop es                  ;Restore registers
  1384.             popa
  1385.             pop bp                  ;Delete stack frame
  1386.             ret 4                   ;Return
  1387.  
  1388. EndP        putbit
  1389.  
  1390. ;****************** getbits() -- Get bits from bit-file
  1391. ;int getbits(int bfp, int count);
  1392.  
  1393. bfp         equ bp+6
  1394. count       equ bp+4
  1395.  
  1396. Proc        getbits
  1397.  
  1398.             push bp                 ;Set up stack frame
  1399.             mov bp,sp
  1400.             push es cx dx           ;Save registers
  1401.  
  1402.             mov es,[bfp]            ;ES = bit-file
  1403.             cmp [word es:2],0       ;Output file, can't input
  1404.             jne p5_done
  1405.  
  1406.             mov cx,[count]          ;CX = bit count
  1407.             xor dx,dx               ;Zero buffer
  1408.  
  1409. p5_loop:    cmp [byte es:5],80h     ;Buffer empty?
  1410.             jne p5_skip1
  1411.  
  1412.             push [word es:0]        ;Get char
  1413.             call fgetc
  1414.             mov [es:4],al           ;Save char
  1415.  
  1416. p5_skip1:   mov al,[es:4]           ;Get bit
  1417.             and al,[es:5]
  1418.             ror [byte es:5],1       ;Move to next bit
  1419.  
  1420. p5_skip2:   add dx,dx               ;Shift over
  1421.             test al,al              ;If bit = 1,
  1422.             jz $+3                  ;then add it in
  1423.             inc dx
  1424.             loop p5_loop            ;Loop back
  1425.  
  1426.             xchg ax,dx              ;AX = result
  1427.  
  1428. p5_done:    pop dx cx es            ;Restore registers
  1429.             pop bp                  ;Delete stack frame
  1430.             ret 4                   ;Return
  1431.  
  1432. EndP        getbits
  1433.  
  1434. ;****************** putbits() -- Put bits to bit-file
  1435. ;int putbits(int bfp, int code, int count);
  1436.  
  1437. bfp         equ bp+8
  1438. code        equ bp+6
  1439. count       equ bp+4
  1440.  
  1441. Proc        putbits
  1442.  
  1443.             push bp                 ;Set up stack frame
  1444.             mov bp,sp
  1445.             pusha                   ;Save all registers
  1446.  
  1447.             mov bx,[bfp]            ;BX = bit-file
  1448.             mov cx,[count]          ;CX = bit count
  1449.             mov dx,[code]           ;DX = code
  1450.             ror dx,cl               ;Put at left
  1451.  
  1452. p6_loop:    add dx,dx               ;Shift out bit
  1453.             sbb ax,ax               ;AX = bit
  1454.             push bx ax              ;Put bit
  1455.             call putbit
  1456.             loop p6_loop            ;Loop back
  1457.  
  1458.             popa                    ;Restore registers
  1459.             pop bp                  ;Delete stack frame
  1460.             ret 6                   ;Return
  1461.  
  1462. EndP        putbits
  1463.  
  1464. ;****************** getcode() -- Get optimal code from bit-file
  1465. ;int getcode(int bfp, int max);  'max' is number of possible codes
  1466.  
  1467. bfp         equ bp+6
  1468. max         equ bp+4
  1469.  
  1470. Proc        getcode
  1471.  
  1472.             push bp                 ;Set up stack frame
  1473.             mov bp,sp
  1474.             push bx cx dx si        ;Save registers
  1475.  
  1476.             bsr cx,[max]            ;CX = log2(max) + 1;
  1477.             jz p7_done              ;Quit on 0
  1478.  
  1479.             mov si,1                ;SI = 2^CX - max
  1480.             shl si,cl
  1481.             sub si,[max]
  1482.  
  1483.             mov bx,[bfp]            ;BX = bit-file
  1484.             dec cx                  ;CX = count (log2(max))
  1485.  
  1486.             push bx cx              ;Get bits
  1487.             call getbits
  1488.             xchg ax,dx              ;Result in DX
  1489.  
  1490.             cmp dx,si               ;DX >= SI?
  1491.             jb p7_done
  1492.  
  1493.             push bx                 ;Add in another bit
  1494.             call getbit
  1495.             add dx,dx
  1496.             add dx,ax
  1497.             sub dx,si               ;Subtract out SI
  1498.  
  1499. p7_done:    xchg ax,dx              ;AX = result
  1500.             pop si dx cx bx         ;Restore registers
  1501.             pop bp                  ;Delete stack frame
  1502.             ret 4                   ;Return
  1503.  
  1504. EndP        getcode
  1505.  
  1506. ;****************** putcode() -- Put optimal code to bit-file
  1507. ;                                'max' is number of possible codes
  1508. ;int putcode(int bfp, int code, int max);
  1509.  
  1510. bfp         equ bp+8
  1511. code        equ bp+6
  1512. max         equ bp+4
  1513.  
  1514. Proc        putcode
  1515.  
  1516.             push bp                 ;Set up stack frame
  1517.             mov bp,sp
  1518.             pusha                   ;Save all registers
  1519.  
  1520.             bsr cx,[max]            ;CX = log2(max) + 1;
  1521.             jz p7_done              ;Quit on 0
  1522.  
  1523.             mov si,1                ;SI = 2^CX - max
  1524.             shl si,cl
  1525.             sub si,[max]
  1526.  
  1527.             mov dx,[code]           ;DX = code
  1528.             dec cx                  ;CX = bit count
  1529.  
  1530.             cmp dx,si               ;DX >= SI?
  1531.             jb p8_skip
  1532.             inc cx                  ;One more bit
  1533.             add dx,si               ;and add in SI
  1534.  
  1535. p8_skip:    push [word bfp] dx cx   ;Output bit code
  1536.             call putbits
  1537.  
  1538. p8_done:    popa                    ;Restore registers
  1539.             pop bp                  ;Delete stack frame
  1540.             ret 4                   ;Return
  1541.  
  1542. EndP        putcode
  1543.  
  1544. End
  1545.  
  1546. ~~~C_MEMORY
  1547. Ideal
  1548.  
  1549. Extrn       TopByte:Word
  1550. Public      allocmem,freemem,getmfree
  1551.  
  1552. Model Tiny
  1553. P386
  1554. CodeSeg
  1555.  
  1556. ;****************** allocmem() -- Allocate memory
  1557. ;void *allocmem(unsigned nbytes);
  1558.  
  1559. nbytes      equ bp+4
  1560.  
  1561. Proc        allocmem
  1562.  
  1563.             push bp                 ;Set up stack frame
  1564.             mov bp,sp
  1565.             push bx cx dx si        ;Save registers
  1566.  
  1567.             mov dx,[bp+4]           ;DX = num. of bytes + 3
  1568.             add dx,3
  1569.             mov bx,offset TopByte   ;BX = first MCB
  1570.  
  1571. p1_loop:    mov cl,[bx+2]           ;CX = flag byte
  1572.             test cl,1               ;Not free, loop
  1573.             jnz p1_lb
  1574.             mov ax,[bx]             ;AX = size
  1575.             cmp ax,dx               ;Big enough?
  1576.             jae p1_gotit
  1577.  
  1578. p1_lb:      test cl,2               ;Last block?
  1579.             jnz p1_nope             ;Out of memory
  1580.             add bx,[bx]             ;Next block
  1581.             jmp p1_loop             ;Loop back
  1582.  
  1583. p1_gotit:   sub ax,3                ;Check for snug fit,
  1584.             cmp ax,dx               ;that is, too little
  1585.             jbe p1_snug             ;excess to split it
  1586.  
  1587.             sub ax,dx               ;AX = excess
  1588.             add ax,3
  1589.  
  1590.             mov si,bx               ;SI = split point
  1591.             add si,dx
  1592.             mov [si],ax             ;Set size of excess block
  1593.             mov [si+2],cl           ;Set flags to original values
  1594.  
  1595.             mov [bx],dx             ;Set size of present block
  1596.             mov [byte bx+2],1       ;Set flags: allocated, not last
  1597.             jmp p1_finish
  1598.  
  1599. p1_snug:    or [byte bx+2],1        ;Set allocated flag
  1600.  
  1601. p1_finish:  xchg ax,bx              ;AX = offset of memory block
  1602.             add ax,3
  1603.  
  1604. p1_done:    pop si dx cx bx         ;Restore registers
  1605.             pop bp                  ;Delete stack frame
  1606.             ret 2                   ;Return
  1607.  
  1608. p1_nope:    xor ax,ax               ;Return null pointer
  1609.             jmp p1_done
  1610.  
  1611. EndP        allocmem
  1612.  
  1613. ;****************** freemem() -- Free memory
  1614. ;void freemem(void *ptr);
  1615.  
  1616. ptr         equ bp+4
  1617.  
  1618. Proc        freemem
  1619.  
  1620.             push bp                 ;Set up stack frame
  1621.             mov bp,sp
  1622.             pusha                   ;Save registers
  1623.  
  1624.             mov dx,[ptr]            ;DX = pointer
  1625.             sub dx,3                ;Point to MCB
  1626.             mov bx,offset TopByte   ;BX = first MCB
  1627.             xor si,si               ;Zero previous ptr.
  1628.  
  1629. p2_loop:    cmp bx,dx               ;Found it?
  1630.             je p2_gotit
  1631.  
  1632.             test [byte bx+2],2      ;Last block?
  1633.             jnz p2_done
  1634.             mov si,bx               ;Save block
  1635.             add bx,[bx]             ;Next block
  1636.             jmp p2_loop             ;Loop back
  1637.  
  1638. p2_gotit:   mov di,bx               ;DI = next block
  1639.             add di,[bx]
  1640.  
  1641.             test [byte bx+2],2      ;Next block allocated
  1642.             jnz p2_cont1            ;or nonexistent, can't
  1643.             mov cl,[di+2]           ;merge with it
  1644.             test cl,1
  1645.             jnz p2_done
  1646.  
  1647.             mov ax,[di]             ;Merge blocks: sum sizes,
  1648.             add [bx],ax             ;set flags of second one
  1649.             mov [bx+2],cl
  1650.  
  1651. p2_cont1:   and [byte bx+2],0FEh    ;Reset allocated flag
  1652.  
  1653.             test si,si              ;Prev. block allocated
  1654.             jz p2_done              ;or nonexistent, can't
  1655.             mov cl,[si+2]           ;merge with it
  1656.             test cl,1
  1657.             jnz p2_done
  1658.  
  1659.             mov ax,[bx]            ;Merge blocks: sum sizes,
  1660.             add [si],ax            ;set flags of second one
  1661.             mov cl,[bx+2]
  1662.             mov [si],cl
  1663.  
  1664. p2_done:    popa                    ;Restore registers
  1665.             pop bp                  ;Delete stack frame
  1666.             ret 2                   ;Return
  1667.  
  1668. EndP        freemem
  1669.  
  1670. ;****************** getmfree() -- Return largest free memory block
  1671. ;unsigned getmfree(void);
  1672.  
  1673. ptr         equ bp+4
  1674.  
  1675. Proc        getmfree
  1676.  
  1677.             push bp                 ;Set up stack frame
  1678.             mov bp,sp
  1679.             push bx                 ;Save registers
  1680.  
  1681.             mov bx,offset TopByte   ;BX = first MCB
  1682.             xor ax,ax               ;Zero counter
  1683.  
  1684. p3_loop:    test [byte bx+2],1      ;Not free, skip
  1685.             jnz p3_skip
  1686.             cmp ax,[bx]             ;Biggest so far?
  1687.             jae p3_skip
  1688.             mov ax,[bx]             ;Save largest block
  1689.  
  1690. p3_skip:    test [byte bx+2],2      ;Last block?
  1691.             jnz p3_done
  1692.             add bx,[bx]             ;Next block
  1693.             jmp p3_loop             ;Loop back
  1694.  
  1695. p3_done:    sub ax,3                ;Adjust to true size
  1696.             pop bx                  ;Restore registers
  1697.             pop bp                  ;Delete stack frame
  1698.             ret                     ;Return
  1699.  
  1700. EndP        getmfree
  1701.  
  1702. End
  1703.  
  1704. ~~~C_FARMEM
  1705. Ideal
  1706.  
  1707. Public      faralloc,farfree,getfarfree
  1708.  
  1709. Model Tiny
  1710. P386
  1711. CodeSeg
  1712.  
  1713. ;****************** faralloc() -- Allocate far memory
  1714. ;int faralloc(int nparas);
  1715.  
  1716. nparas      equ bp+4
  1717.  
  1718. Proc        faralloc
  1719.  
  1720.             push bp                 ;Set up stack frame
  1721.             mov bp,sp
  1722.             push bx                 ;Save BX
  1723.  
  1724.             mov ah,48h              ;Allocate memory
  1725.             mov bx,[nparas]         ;BX = paras
  1726.             int 21h                 ;DOS call
  1727.  
  1728.             jnc $+4                 ;No error, return pointer
  1729.             xor ax,ax               ;Error, return 0
  1730.  
  1731.             pop bx                  ;Restore BX
  1732.             pop bp                  ;Delete stack frame
  1733.             ret 2                   ;Return
  1734.  
  1735. EndP        faralloc
  1736.  
  1737. ;****************** farfree() -- Free far memory
  1738. ;void farfree(int ptr);
  1739.  
  1740. ptr         equ bp+4
  1741.  
  1742. Proc        farfree
  1743.  
  1744.             push bp                 ;Set up stack frame
  1745.             mov bp,sp
  1746.             push es ax              ;Save registers
  1747.  
  1748.             mov ah,4Ah              ;Free memory
  1749.             mov es,[ptr]            ;ES = pointer
  1750.             int 21h                 ;DOS call
  1751.  
  1752.             pop ax es               ;Restore registers
  1753.             pop bp                  ;Delete stack frame
  1754.             ret 2                   ;Return
  1755.  
  1756. EndP        farfree
  1757.  
  1758. ;****************** getfarfree() -- Return largest free far memory block
  1759. ;unsigned getfarfree(void);
  1760.  
  1761. ptr         equ bp+4
  1762.  
  1763. Proc        getfarfree
  1764.  
  1765.             push bp                 ;Set up stack frame
  1766.             mov bp,sp
  1767.             push bx                 ;Save registers
  1768.  
  1769.             mov ah,48h              ;Allocate memory
  1770.             mov bx,-1               ;-1 is invalid
  1771.             int 21h                 ;DOS call (returns an error)
  1772.             xchg ax,bx              ;AX = size of largest free block
  1773.  
  1774.             pop bx                  ;Restore registers
  1775.             pop bp                  ;Delete stack frame
  1776.             ret                     ;Return
  1777.  
  1778. EndP        getfarfree
  1779.  
  1780. End
  1781.  
  1782. ~~~C_ATOI
  1783. Ideal
  1784.  
  1785. Public      atoi,atol
  1786.  
  1787. Model Tiny
  1788. CodeSeg
  1789. P386
  1790.  
  1791. ;****************** atoi() -- Convert string to int
  1792. ;int atoi(char *strp);
  1793.  
  1794. strp        equ bp+4
  1795.  
  1796. Proc        atoi
  1797.  
  1798.             push bp                 ;Set up stack frame
  1799.             mov bp,sp
  1800.  
  1801.             push dx [word strp]     ;Save DX, call atol
  1802.             call atol
  1803.  
  1804.             pop dx                  ;Restore DX
  1805.             pop bp                  ;Delete stack frame
  1806.             ret 2                   ;Return
  1807.  
  1808. EndP        atoi
  1809.  
  1810. ;****************** atol() -- Convert string to long
  1811. ;long atol(char *strp);
  1812.  
  1813. strp        equ bp+4
  1814.  
  1815. Proc        atol
  1816.  
  1817.             push bp                 ;Set up stack frame
  1818.             mov bp,sp
  1819.             push si di ebx ecx      ;Save registers
  1820.  
  1821.             mov si,[strp]           ;SI = string
  1822.  
  1823.             xor ecx,ecx             ;ECX = 0
  1824.             xor ebx,ebx             ;EBX = 0
  1825.  
  1826. p1_ploop:   mov bl,[si]             ;Load char
  1827.             inc si
  1828.             cmp bl,' '              ;Loop while char is space
  1829.             je p1_ploop             ;(20h, or 09h thru 0Dh)
  1830.             cmp bl,9
  1831.             jna p1_cont
  1832.             cmp bl,13
  1833.             jbe p1_ploop
  1834.  
  1835. p1_cont:    xor di,di               ;DI = 0
  1836.             cmp bl,'+'              ;If char = '+', ignore
  1837.             je p1_loop
  1838.             cmp bl,'-'              ;If char <> '-', keep it
  1839.             jne p1_skip
  1840.             inc di                  ;Set negative flag
  1841.  
  1842. p1_loop:    mov bl,[si]             ;Load char
  1843.             inc si
  1844.  
  1845. p1_skip:    cmp bl,'9'              ;Not a digit, finish
  1846.             ja p1_finish
  1847.             sub bl,'0'
  1848.             jc p1_finish
  1849.  
  1850.             imul ecx,10             ;Multiply by 10
  1851.             add ecx,ebx             ;Add in digit...
  1852.             jmp p1_loop             ;Loop back
  1853.  
  1854. p1_finish:  xchg ax,cx              ;DX:AX = result
  1855.             shr ecx,16
  1856.             mov dx,cx
  1857.             dec di                  ;Positive, don't negate
  1858.             jl p1_done
  1859.  
  1860.             neg dx                  ;Negate the result
  1861.             neg ax
  1862.             sbb dx,0
  1863.  
  1864. p1_done:    pop ecx ebx di si       ;Restore registers
  1865.             pop bp                  ;Delete stack frame
  1866.             ret 2                   ;Return
  1867.  
  1868. EndP        atol
  1869.  
  1870. End
  1871.  
  1872. ~~~C_ITOA
  1873. Ideal
  1874.  
  1875. Public      itoa
  1876.  
  1877. Model Tiny
  1878. CodeSeg
  1879. P386
  1880.  
  1881. ;****************** itoa() -- Convert int to string
  1882. ;void itoa(int n, char *strp);
  1883.  
  1884. n           equ bp+6
  1885. strp        equ bp+4
  1886.  
  1887. Proc        itoa
  1888.  
  1889.             push bp                 ;Set up stack frame
  1890.             mov bp,sp
  1891.             pusha                   ;Save all registers
  1892.  
  1893.             mov ax,[n]              ;AX = n
  1894.             mov di,[strp]           ;DI = string pointer
  1895.  
  1896.             test ax,ax              ;Negative?
  1897.             jge p1_noneg
  1898.             mov [byte di],'-'       ;Store minus sign
  1899.             inc di
  1900.             neg ax                  ;Make it positive
  1901.  
  1902. p1_noneg:   xor cx,cx               ;Zero CX
  1903.             test ax,ax              ;Check for zero
  1904.             jnz p1_nozero
  1905.  
  1906.             push '0'                ;Push a zero
  1907.             inc cx                  ;One digit
  1908.             jmp p1_ploop
  1909.  
  1910. p1_nozero:  mov si,10               ;SI = 10
  1911.  
  1912. p1_dloop:   xor dx,dx               ;Divide by 10
  1913.             div si
  1914.             mov bl,dl               ;Remainder in BL
  1915.             add bl,30h              ;Convert to digit
  1916.             push bx                 ;Push digit
  1917.             inc cx
  1918.             test ax,ax              ;Loop back
  1919.             jnz p1_dloop
  1920.  
  1921. p1_ploop:   pop ax                  ;Pop digit
  1922.             mov [di],al             ;Store digit
  1923.             inc di
  1924.             loop p1_ploop           ;Loop back
  1925.  
  1926.             mov [byte di],0         ;Add the null byte
  1927.  
  1928.             popa                    ;Restore registers
  1929.             pop bp                  ;Delete stack frame
  1930.             ret 4                   ;Return
  1931.  
  1932. EndP        itoa
  1933.  
  1934. End
  1935.  
  1936. ~~~C_LTOA
  1937. Ideal
  1938.  
  1939. Extrn       itoa:near
  1940. Public      ltoa
  1941.  
  1942. Model Tiny
  1943. CodeSeg
  1944. P386
  1945.  
  1946. ;****************** ltoa() -- Convert long to string
  1947. ;void ltoa(long n, char *strp);
  1948.  
  1949. n           equ bp+6
  1950. strp        equ bp+4
  1951.  
  1952. Proc        ltoa
  1953.  
  1954.             push bp                 ;Set up stack frame
  1955.             mov bp,sp
  1956.             pushad                  ;Save all registers
  1957.  
  1958.             mov eax,[n]             ;EAX = n
  1959.             mov di,[strp]           ;DI = string pointer
  1960.  
  1961.             test eax,eax            ;Negative?
  1962.             jge p1_noneg
  1963.             mov [byte di],'-'       ;Store minus sign
  1964.             inc di
  1965.             neg eax                 ;Make it positive
  1966.  
  1967. p1_noneg:   xor cx,cx               ;Zero CX
  1968.             test eax,eax            ;Check for zero
  1969.             jnz p1_nozero
  1970.  
  1971.             push '0'                ;Push a zero
  1972.             inc cx                  ;One digit
  1973.             jmp p1_ploop
  1974.  
  1975. p1_nozero:  mov si,10               ;SI = 10
  1976.  
  1977. p1_dloop:   xor edx,edx             ;Divide by 10
  1978.             div si
  1979.             mov bl,dl               ;Remainder in BL
  1980.             add bl,30h              ;Convert to digit
  1981.             push bx                 ;Push digit
  1982.             inc cx
  1983.             test eax,eax            ;Loop back
  1984.             jnz p1_dloop
  1985.  
  1986. p1_ploop:   pop ax                  ;Pop digit
  1987.             mov [di],al             ;Store digit
  1988.             inc di
  1989.             loop p1_ploop           ;Loop back
  1990.  
  1991.             mov [byte di],0         ;Add the null byte
  1992.  
  1993.             popad                   ;Restore registers
  1994.             pop bp                  ;Delete stack frame
  1995.             ret 6                   ;Return
  1996.  
  1997. EndP        ltoa
  1998.  
  1999. End
  2000.  
  2001. ~~~C_PUTS
  2002. Ideal
  2003.  
  2004. Extrn       PUT_CHAR:near
  2005. Public      puts,xputs
  2006.  
  2007. Model Tiny
  2008. CodeSeg
  2009. P386
  2010.  
  2011. ;****************** puts() -- Print string
  2012. ;void puts(char *strp);
  2013.  
  2014. strp        equ bp+4
  2015.  
  2016. Proc        puts
  2017.  
  2018.             push bp                 ;Set up stack frame
  2019.             mov bp,sp
  2020.             pusha                   ;Save all registers
  2021.  
  2022.             mov si,[strp]           ;SI = string pointer
  2023.  
  2024. p1_loop:    lodsb                   ;Get char
  2025.             test al,al              ;Check for null
  2026.             jz p1_done
  2027.             call PUT_CHAR           ;Output char
  2028.             jmp p1_loop             ;Loop back
  2029.  
  2030. p1_done:    popa                    ;Restore registers
  2031.             pop bp                  ;Delete stack frame
  2032.             ret 2                   ;Return
  2033.  
  2034. EndP        puts
  2035.  
  2036. ;****************** xputs() -- Print string, generalized
  2037. ;void xputs(void *func, int strp);
  2038.  
  2039. func        equ bp+6
  2040. strp        equ bp+4
  2041.  
  2042. Proc        xputs
  2043.  
  2044.             push bp                 ;Set up stack frame
  2045.             mov bp,sp
  2046.             pusha                   ;Save all registers
  2047.  
  2048.             mov si,[strp]           ;SI = string pointer
  2049.             mov bx,[func]           ;BX = function
  2050.  
  2051. p2_loop:    lodsb                   ;Get char
  2052.             test al,al              ;Check for null
  2053.             jz p2_done
  2054.             push ax                 ;Output char
  2055.             call bx
  2056.             jmp p2_loop             ;Loop back
  2057.  
  2058. p2_done:    popa                    ;Restore registers
  2059.             pop bp                  ;Delete stack frame
  2060.             ret 4                   ;Return
  2061.  
  2062. EndP        xputs
  2063.  
  2064. End
  2065.  
  2066. ~~~C_FPUTS
  2067. Ideal
  2068.  
  2069. Extrn       fputc:near
  2070. Public      fputs
  2071.  
  2072. Model Tiny
  2073. CodeSeg
  2074. P386
  2075.  
  2076. ;****************** fputs() -- Print string to file
  2077. ;int fputs(int fp, char *strp);
  2078.  
  2079. fp          equ bp+6
  2080. strp        equ bp+4
  2081.  
  2082. Proc        fputs
  2083.  
  2084.             push bp                 ;Set up stack frame
  2085.             mov bp,sp
  2086.             push bx si              ;Save registers
  2087.  
  2088.             mov si,[strp]           ;SI = string pointer
  2089.             mov bx,[fp]             ;BX = file pointer
  2090.  
  2091. p1_loop:    lodsb                   ;Get char
  2092.             test al,al              ;Check for null
  2093.             jz p1_done
  2094.             push bx ax              ;Output char:
  2095.             call fputc              ;fputc(fp, AX);
  2096.             test ax,ax
  2097.             jnl p1_loop             ;Loop back
  2098.  
  2099. p1_done:    pop si bx               ;Restore registers
  2100.             pop bp                  ;Delete stack frame
  2101.             ret 4                   ;Return
  2102.  
  2103. EndP        fputs
  2104.  
  2105. End
  2106.  
  2107. ~~~C_GETS
  2108. Ideal
  2109.  
  2110. Public      gets,xgets
  2111.  
  2112. Model Tiny
  2113. CodeSeg
  2114. P386
  2115.  
  2116. ;****************** gets() -- Get string
  2117. ;void gets(char *strp, int max);
  2118.  
  2119. strp        equ bp+6
  2120. max         equ bp+4
  2121.  
  2122. Proc        gets
  2123.  
  2124.             push bp                 ;Set up stack frame
  2125.             mov bp,sp
  2126.             pusha                   ;Save all registers
  2127.             push es
  2128.  
  2129.             mov di,[strp]           ;DI = string pointer
  2130.             mov cx,[max]            ;CX = max string length
  2131.             dec cx
  2132.  
  2133. p1_loop:    xor ax,ax               ;Get key
  2134.             int 16h
  2135.             test al,al              ;Ignore extended keys
  2136.             jz p1_loop
  2137.             cmp al,8                ;Backspace?
  2138.             je p1_bksp
  2139.  
  2140.             int 29h                 ;Show char (on screen)
  2141.             cmp al,13               ;<Enter> = done
  2142.             je p1_done
  2143.             jcxz p1_loop            ;Maxed out, don't store
  2144.             mov [di],al             ;Store char
  2145.             inc di
  2146.             dec cx                  ;Decrement maximum
  2147.             jmp p1_loop             ;Loop back
  2148.  
  2149. p1_bksp:    cmp di,[strp]           ;At beginning, do nothing
  2150.             je p1_loop
  2151.             dec di                  ;Decrement string pointer
  2152.             inc cx                  ;Increment maximum
  2153.  
  2154.             push cx                 ;Save CX
  2155.             mov ah,0Fh              ;Get video page
  2156.             int 10h
  2157.             mov ah,3                ;Get cursor position
  2158.             int 10h                 ;in DH/DL
  2159.             dec dx                  ;Move left one column
  2160.             test dl,dl              ;if at zero moves up too
  2161.             jnl p1_nowrap
  2162.  
  2163.             push 0                  ;DL = last column
  2164.             pop es
  2165.             mov dl,[es:044Ah]
  2166.             dec dx
  2167.  
  2168. p1_nowrap:  mov ah,2                ;Set cursor position
  2169.             int 10h
  2170.             mov ax,0A20h            ;Clear char at current
  2171.             mov cx,1                ;cursor position
  2172.             int 10h
  2173.             pop cx                  ;Restore CX
  2174.             jmp p1_loop             ;Loop back
  2175.  
  2176. p1_done:    mov al,10               ;Output LF
  2177.             int 29h
  2178.             mov [byte di],0         ;Terminate string
  2179.             pop es                  ;Restore registers
  2180.             popa
  2181.             pop bp                  ;Delete stack frame
  2182.             ret 4                   ;Return
  2183.  
  2184. EndP        gets
  2185.  
  2186. ;****************** xgets() -- Get string, generalized
  2187. ;void xgets(void *func, char *strp, int max, int term);
  2188.  
  2189. strp        equ bp+10
  2190. func        equ bp+8
  2191. max         equ bp+6
  2192. term        equ bp+4
  2193.  
  2194. Proc        xgets
  2195.  
  2196.             push bp                 ;Set up stack frame
  2197.             mov bp,sp
  2198.             pusha                   ;Save all registers
  2199.  
  2200.             mov di,[strp]           ;DI = string pointer
  2201.             mov bx,[func]           ;BX = function
  2202.             mov cx,[max]            ;CX = max string length
  2203.             dec cx
  2204.             mov dx,[term]           ;DX = terminator
  2205.  
  2206. p2_loop:    call bx                 ;Get char
  2207.             cmp al,dl               ;Check for terminator
  2208.             je p2_done
  2209.             jcxz p1_loop            ;Maxed out, don't store
  2210.             mov [di],al             ;Store char
  2211.             inc di
  2212.             dec cx                  ;Decrement maximum
  2213.             jmp p2_loop             ;Loop back
  2214.  
  2215. p2_done:    mov [byte di],0         ;Terminate string
  2216.             popa                    ;Restore registers
  2217.             pop bp                  ;Delete stack frame
  2218.             ret 8                   ;Return
  2219.  
  2220. EndP        xgets
  2221.  
  2222. End
  2223.  
  2224. ~~~C_FGETS
  2225. Ideal
  2226.  
  2227. Extrn       fgetc:near
  2228. Public      fgets
  2229.  
  2230. Model Tiny
  2231. CodeSeg
  2232. P386
  2233.  
  2234. ;****************** fgets() -- Get string from file
  2235. ;void fgets(int fp, char *strp, int max);
  2236.  
  2237. fp          equ bp+8
  2238. strp        equ bp+6
  2239. max         equ bp+4
  2240.  
  2241. Proc        fgets
  2242.  
  2243.             push bp                 ;Set up stack frame
  2244.             mov bp,sp
  2245.             push bx cx dx di        ;Save all registers
  2246.  
  2247.             mov di,[strp]           ;DI = string pointer
  2248.             mov bx,[fp]             ;BX = file pointer
  2249.             mov cx,[max]            ;CX = max string length
  2250.             dec cx
  2251.  
  2252. p1_loop:    push bx                 ;Get char
  2253.             call fgetc
  2254.             test ax,ax              ;Check for EOF
  2255.             jl p1_quit
  2256.             cmp al,13               ;CR = done
  2257.             je p1_done
  2258.             jcxz p1_loop            ;Maxed out, don't store
  2259.             mov [di],al             ;Store char
  2260.             inc di
  2261.             dec cx                  ;Decrement maximum
  2262.             jmp p1_loop             ;Loop back
  2263.  
  2264. p1_done:    push bx                 ;Remove LF
  2265.             call fgetc
  2266.             xor ax,ax
  2267. p1_quit:    mov [byte di],0         ;Terminate string
  2268.             pop di dx cx bx         ;Restore registers
  2269.             pop bp                  ;Delete stack frame
  2270.             ret 6                   ;Return
  2271.  
  2272. EndP        fgets
  2273.  
  2274. End
  2275.  
  2276. ~~~C_PRTBUF
  2277. Ideal
  2278.  
  2279. Public      PRT_BUF
  2280.  
  2281. Model Tiny
  2282. CodeSeg
  2283. P386
  2284.  
  2285. ;****************** PRT_BUF -- String buffer for printf(), etc.
  2286.  
  2287. PRT_BUF     db 20 dup(0)
  2288.  
  2289. End
  2290.  
  2291. ~~~C_PRINTF
  2292. Ideal
  2293.  
  2294. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2295. Extrn       PUT_CHAR:near
  2296. Public      printf
  2297.  
  2298. Model Tiny
  2299. CodeSeg
  2300. P386
  2301.  
  2302. ;****************** printf() -- Print formatted string
  2303. ;void printf(char *fmt, void *args);
  2304.  
  2305. fmt         equ bp+6
  2306. args        equ bp+4
  2307.  
  2308. Proc        printf
  2309.  
  2310.             push bp                 ;Set up stack frame
  2311.             mov bp,sp
  2312.             pusha                   ;Save all registers
  2313.  
  2314.             mov si,[fmt]            ;SI = string pointer
  2315.             mov bx,[args]           ;BX = arg pointer
  2316.  
  2317. p1_loop:    lodsb                   ;Get char
  2318.             test al,al              ;Check for null
  2319.             jz p1_done
  2320.             cmp al,'%'              ;Check for '%'
  2321.             je p1_proc
  2322. p1_putc:    call PUT_CHAR           ;Output char
  2323.             jmp p1_loop             ;Loop back
  2324.  
  2325. p1_proc:    lodsb                   ;Get char
  2326.             test al,al              ;Check for null
  2327.             jz p1_done
  2328.             cmp al,'%'              ; %% = percent
  2329.             je p1_putc
  2330.             cmp al,'d'              ; %d = integer
  2331.             je p1_int
  2332.             cmp al,'l'              ; %l = long int
  2333.             je p1_long
  2334.             cmp al,'x'              ; %x = hex
  2335.             je p1_hex
  2336.             cmp al,'c'              ; %c = char
  2337.             je p1_char
  2338.             cmp al,'s'              ; %s = string
  2339.             je p1_str
  2340.             jmp p1_loop             ;Invalid, ignore
  2341.  
  2342. p1_done:    popa                    ;Restore registers
  2343.             pop bp                  ;Delete stack frame
  2344.             ret 4                   ;Return
  2345.  
  2346. p1_long:    lodsb                   ;Get char
  2347.             test al,al              ;Check for null
  2348.             jz p1_done
  2349.             cmp al,'d'              ; %ld = long integer
  2350.             je p1_lint
  2351.             cmp al,'x'              ; %lx = long hex
  2352.             je p1_lhex
  2353.             jmp p1_loop             ;Invalid, ignore
  2354.  
  2355. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2356.             push offset PRT_BUF
  2357.             call itoa
  2358.             inc bx                  ;Advance pointer
  2359.             inc bx
  2360.             mov di,offset PRT_BUF   ;Print alpha string
  2361.             jmp p1_alpha
  2362.  
  2363. p1_lint:    push [dword bx]          ;ltoa(*bx, PRT_BUF);
  2364.             push offset PRT_BUF
  2365.             call ltoa
  2366.             add bx,4                ;Advance pointer
  2367.             mov di,offset PRT_BUF   ;Print alpha string
  2368.             jmp p1_alpha
  2369.  
  2370. p1_hex:     mov ax,[bx]             ;AX = arg
  2371.             call p1_chex            ;Convert to hex
  2372.             inc bx                  ;Advance pointer
  2373.             inc bx
  2374.             jmp p1_loop             ;Loop back
  2375.  
  2376. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2377.             call p1_chex            ;Convert to hex
  2378.             mov ax,[bx]             ;AX = low word
  2379.             call p1_chex            ;Convert to hex
  2380.             add bx,4                ;Advance pointer
  2381.             jmp p1_loop             ;Loop back
  2382.  
  2383. p1_char:    mov al,[bx]             ;Output char
  2384.             int 29h
  2385.             inc bx                  ;Advance pointer
  2386.             jmp p1_loop             ;Loop back
  2387.  
  2388. p1_str:     mov al,[bx]             ;Get char
  2389.             inc bx                  ;Advance pointer
  2390.             test al,al              ;Check for null
  2391.             jz p1_sdone
  2392.             call PUT_CHAR           ;Output char
  2393.             jmp p1_str              ;Loop back
  2394.  
  2395. p1_sdone:   jmp p1_loop             ;Return to main loop
  2396.  
  2397. p1_alpha:   mov al,[di]             ;Get char
  2398.             test al,al              ;Check for null
  2399.             jz p1_sdone
  2400.             call PUT_CHAR           ;Output char
  2401.             inc di                  ;Advance pointer
  2402.             jmp p1_alpha            ;Loop back
  2403.  
  2404. p1_chex:    mov cx,4                ;4 hex digits
  2405.             xchg al,ah              ;Reverse the order
  2406.             ror ah,cl               ;of the hex digits
  2407.             ror al,cl               ;in AX
  2408.  
  2409. p1_hloop:   push ax                 ;Save AX
  2410.             and al,0Fh              ;Keep 4 bits
  2411.             cmp al,0Ah              ;Compute the hex digit,
  2412.             sbb al,69h              ;using Improved Allison's Algorithm
  2413.             das
  2414.             call PUT_CHAR           ;Output char
  2415.             pop ax                  ;Restore AX
  2416.             shr ax,4                ;Shift it over
  2417.             loop p1_hloop           ;Loop back
  2418.             ret                     ;Return
  2419.  
  2420. EndP        printf
  2421.  
  2422. End
  2423.  
  2424. ~~~C_SPRINT
  2425. Ideal
  2426.  
  2427. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2428. Public      sprintf
  2429.  
  2430. Model Tiny
  2431. CodeSeg
  2432. P386
  2433.  
  2434. ;****************** sprintf() -- Print formatted string into string
  2435. ;void sprintf(char *strp, char *fmt, void *args);
  2436.  
  2437. strp        equ bp+8
  2438. fmt         equ bp+6
  2439. args        equ bp+4
  2440.  
  2441. Proc        sprintf
  2442.  
  2443.             push bp                 ;Set up stack frame
  2444.             mov bp,sp
  2445.             pusha                   ;Save all registers
  2446.  
  2447.             mov di,[strp]           ;DI = string pointer
  2448.             mov si,[fmt]            ;SI = format pointer
  2449.             mov bx,[args]           ;BX = arg pointer
  2450.  
  2451. p1_loop:    lodsb                   ;Get char
  2452.             test al,al              ;Check for null
  2453.             jz p1_done
  2454.             cmp al,'%'              ;Check for '%'
  2455.             je p1_proc
  2456. p1_putc:    stosb                   ;Output char
  2457.             jmp p1_loop             ;Loop back
  2458.  
  2459. p1_proc:    lodsb                   ;Get char
  2460.             test al,al              ;Check for null
  2461.             jz p1_done
  2462.             cmp al,'%'              ; %% = percent
  2463.             je p1_putc
  2464.             cmp al,'d'              ; %d = integer
  2465.             je p1_int
  2466.             cmp al,'l'              ; %l = long int
  2467.             je p1_long
  2468.             cmp al,'x'              ; %x = hex
  2469.             je p1_hex
  2470.             cmp al,'c'              ; %c = char
  2471.             je p1_char
  2472.             cmp al,'s'              ; %s = string
  2473.             je p1_str
  2474.             jmp p1_loop             ;Invalid, ignore
  2475.  
  2476. p1_done:    xor al,al               ;Store a null byte
  2477.             stosb
  2478.             popa                    ;Restore registers
  2479.             pop bp                  ;Delete stack frame
  2480.             ret 6                   ;Return
  2481.  
  2482. p1_long:    lodsb                   ;Get char
  2483.             test al,al              ;Check for null
  2484.             jz p1_done
  2485.             cmp al,'d'              ; %ld = long integer
  2486.             je p1_lint
  2487.             cmp al,'x'              ; %lx = long hex
  2488.             je p1_lhex
  2489.             jmp p1_loop             ;Invalid, ignore
  2490.  
  2491. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2492.             push offset PRT_BUF
  2493.             call itoa
  2494.             inc bx                  ;Advance pointer
  2495.             inc bx
  2496.             mov bp,offset PRT_BUF   ;Print alpha string
  2497.             jmp p1_alpha
  2498.  
  2499. p1_lint:    push [dword bx]          ;ltoa(*bx, PRT_BUF);
  2500.             push offset PRT_BUF
  2501.             call ltoa
  2502.             add bx,4                ;Advance pointer
  2503.             mov bp,offset PRT_BUF   ;Print alpha string
  2504.             jmp p1_alpha
  2505.  
  2506. p1_hex:     mov ax,[bx]             ;AX = arg
  2507.             call p1_chex            ;Convert to hex
  2508.             inc bx                  ;Advance pointer
  2509.             inc bx
  2510.             jmp p1_loop             ;Loop back
  2511.  
  2512. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2513.             call p1_chex            ;Convert to hex
  2514.             mov ax,[bx]             ;AX = low word
  2515.             call p1_chex            ;Convert to hex
  2516.             add bx,4                ;Advance pointer
  2517.             jmp p1_loop             ;Loop back
  2518.  
  2519. p1_char:    mov al,[bx]             ;Output char
  2520.             stosb
  2521.             inc bx                  ;Advance pointer
  2522.             jmp p1_loop             ;Loop back
  2523.  
  2524. p1_str:     mov al,[bx]             ;Get char
  2525.             inc bx                  ;Advance pointer
  2526.             test al,al              ;Check for null
  2527.             jz p1_sdone
  2528.             stosb                   ;Output char
  2529.             jmp p1_str              ;Loop back
  2530.  
  2531. p1_sdone:   jmp p1_loop             ;Return to main loop
  2532.  
  2533. p1_alpha:   mov al,[bp]             ;Get char
  2534.             test al,al              ;Check for null
  2535.             jz p1_sdone
  2536.             stosb                   ;Output char
  2537.             inc bp                  ;Advance pointer
  2538.             jmp p1_alpha            ;Loop back
  2539.  
  2540. p1_chex:    mov cx,4                ;4 hex digits
  2541.             xchg al,ah              ;Reverse the order
  2542.             ror ah,cl               ;of the hex digits
  2543.             ror al,cl               ;in AX
  2544.  
  2545. p1_hloop:   push ax                 ;Save AX
  2546.             and al,0Fh              ;Keep 4 bits
  2547.             cmp al,0Ah              ;Compute the hex digit,
  2548.             sbb al,69h              ;using Improved Allison's Algorithm
  2549.             das
  2550.             stosb                   ;Output char
  2551.             pop ax                  ;Restore AX
  2552.             shr ax,4                ;Shift it over
  2553.             loop p1_hloop           ;Loop back
  2554.             ret                     ;Return
  2555.  
  2556. EndP        sprintf
  2557.  
  2558. End
  2559.  
  2560. ~~~C_FPRINT
  2561. Ideal
  2562.  
  2563. Extrn       PRT_BUF:byte,fputc:near,itoa:near,ltoa:near
  2564. Public      fprintf
  2565.  
  2566. Model Tiny
  2567. CodeSeg
  2568. P386
  2569.  
  2570. ;****************** fprintf() -- Print formatted string to file
  2571. ;void fprintf(int fp, char *fmt, void *args);
  2572.  
  2573. fp          equ bp+8
  2574. fmt         equ bp+6
  2575. args        equ bp+4
  2576.  
  2577. Proc        fprintf
  2578.  
  2579.             push bp                 ;Set up stack frame
  2580.             mov bp,sp
  2581.             pusha                   ;Save all registers
  2582.  
  2583.             mov dx,[fp]             ;DX = file pointer
  2584.             mov si,[fmt]            ;SI = string pointer
  2585.             mov bx,[args]           ;BX = arg pointer
  2586.  
  2587. p1_loop:    lodsb                   ;Get char
  2588.             test al,al              ;Check for null
  2589.             jz p1_done
  2590.             cmp al,'%'              ;Check for '%'
  2591.             je p1_proc
  2592. p1_putc:    push dx ax              ;Output char
  2593.             call fputc
  2594.             jmp p1_loop             ;Loop back
  2595.  
  2596. p1_proc:    lodsb                   ;Get char
  2597.             test al,al              ;Check for null
  2598.             jz p1_done
  2599.             cmp al,'%'              ; %% = percent
  2600.             je p1_putc
  2601.             cmp al,'d'              ; %d = integer
  2602.             je p1_int
  2603.             cmp al,'l'              ; %l = long int
  2604.             je p1_long
  2605.             cmp al,'x'              ; %x = hex
  2606.             je p1_hex
  2607.             cmp al,'c'              ; %c = char
  2608.             je p1_char
  2609.             cmp al,'s'              ; %s = string
  2610.             je p1_str
  2611.             jmp p1_loop             ;Invalid, ignore
  2612.  
  2613. p1_done:    popa                    ;Restore registers
  2614.             pop bp                  ;Delete stack frame
  2615.             ret 6                   ;Return
  2616.  
  2617. p1_long:    lodsb                   ;Get char
  2618.             test al,al              ;Check for null
  2619.             jz p1_done
  2620.             cmp al,'d'              ; %ld = long integer
  2621.             je p1_lint
  2622.             cmp al,'x'              ; %lx = long hex
  2623.             je p1_lhex
  2624.             jmp p1_loop             ;Invalid, ignore
  2625.  
  2626. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2627.             push offset PRT_BUF
  2628.             call itoa
  2629.             inc bx                  ;Advance pointer
  2630.             inc bx
  2631.             mov di,offset PRT_BUF   ;Print alpha string
  2632.             jmp p1_alpha
  2633.  
  2634. p1_lint:    push [dword bx]          ;ltoa(*bx, PRT_BUF);
  2635.             push offset PRT_BUF
  2636.             call ltoa
  2637.             add bx,4                ;Advance pointer
  2638.             mov di,offset PRT_BUF   ;Print alpha string
  2639.             jmp p1_alpha
  2640.  
  2641. p1_hex:     mov ax,[bx]             ;AX = arg
  2642.             call p1_chex            ;Convert to hex
  2643.             inc bx                  ;Advance pointer
  2644.             inc bx
  2645.             jmp p1_loop             ;Loop back
  2646.  
  2647. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2648.             call p1_chex            ;Convert to hex
  2649.             mov ax,[bx]             ;AX = low word
  2650.             call p1_chex            ;Convert to hex
  2651.             add bx,4                ;Advance pointer
  2652.             jmp p1_loop             ;Loop back
  2653.  
  2654. p1_char:    mov al,[bx]             ;Output char
  2655.             push dx ax
  2656.             call fputc
  2657.             inc bx                  ;Advance pointer
  2658.             jmp p1_loop             ;Loop back
  2659.  
  2660. p1_str:     mov al,[bx]             ;Get char
  2661.             inc bx                  ;Advance pointer
  2662.             test al,al              ;Check for null
  2663.             jz p1_sdone
  2664.             push dx ax              ;Output char
  2665.             call fputc
  2666.             jmp p1_str              ;Loop back
  2667.  
  2668. p1_sdone:   jmp p1_loop             ;Return to main loop
  2669.  
  2670. p1_alpha:   mov al,[di]             ;Get char
  2671.             test al,al              ;Check for null
  2672.             jz p1_sdone
  2673.             push dx ax              ;Output char
  2674.             call fputc
  2675.             inc di                  ;Advance pointer
  2676.             jmp p1_alpha            ;Loop back
  2677.  
  2678. p1_chex:    mov cx,4                ;4 hex digits
  2679.             xchg al,ah              ;Reverse the order
  2680.             ror ah,cl               ;of the hex digits
  2681.             ror al,cl               ;in AX
  2682.  
  2683. p1_hloop:   push ax                 ;Save AX
  2684.             and al,0Fh              ;Keep 4 bits
  2685.             cmp al,0Ah              ;Compute the hex digit,
  2686.             sbb al,69h              ;using Improved Allison's Algorithm
  2687.             das
  2688.             push dx ax              ;Output char
  2689.             call fputc
  2690.             pop ax                  ;Restore AX
  2691.             shr ax,4                ;Shift it over
  2692.             loop p1_hloop           ;Loop back
  2693.             ret                     ;Return
  2694.  
  2695. EndP        fprintf
  2696.  
  2697. End
  2698.  
  2699. ~~~C_XPRINT
  2700. Ideal
  2701.  
  2702. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2703. Public      xprintf
  2704.  
  2705. Model Tiny
  2706. CodeSeg
  2707. P386
  2708.  
  2709. ;****************** xprintf() -- Print formatted string, generalized
  2710. ;void xprintf(void *func, char *fmt, void *args);
  2711.  
  2712. func        equ bp+8
  2713. fmt         equ bp+6
  2714. args        equ bp+4
  2715.  
  2716. Proc        xprintf
  2717.  
  2718.             push bp                 ;Set up stack frame
  2719.             mov bp,sp
  2720.             pusha                   ;Save all registers
  2721.  
  2722.             mov dx,[func]           ;DX = function pointer
  2723.             mov si,[fmt]            ;SI = string pointer
  2724.             mov bx,[args]           ;BX = arg pointer
  2725.  
  2726. p1_loop:    lodsb                   ;Get char
  2727.             test al,al              ;Check for null
  2728.             jz p1_done
  2729.             cmp al,'%'              ;Check for '%'
  2730.             je p1_proc
  2731. p1_putc:    push ax                 ;Output char
  2732.             call dx
  2733.             jmp p1_loop             ;Loop back
  2734.  
  2735. p1_proc:    lodsb                   ;Get char
  2736.             test al,al              ;Check for null
  2737.             jz p1_done
  2738.             cmp al,'%'              ; %% = percent
  2739.             je p1_putc
  2740.             cmp al,'d'              ; %d = integer
  2741.             je p1_int
  2742.             cmp al,'l'              ; %l = long int
  2743.             je p1_long
  2744.             cmp al,'x'              ; %x = hex
  2745.             je p1_hex
  2746.             cmp al,'c'              ; %c = char
  2747.             je p1_char
  2748.             cmp al,'s'              ; %s = string
  2749.             je p1_str
  2750.             jmp p1_loop             ;Invalid, ignore
  2751.  
  2752. p1_done:    popa                    ;Restore registers
  2753.             pop bp                  ;Delete stack frame
  2754.             ret 6                   ;Return
  2755.  
  2756. p1_long:    lodsb                   ;Get char
  2757.             test al,al              ;Check for null
  2758.             jz p1_done
  2759.             cmp al,'d'              ; %ld = long integer
  2760.             je p1_lint
  2761.             cmp al,'x'              ; %lx = long hex
  2762.             je p1_lhex
  2763.             jmp p1_loop             ;Invalid, ignore
  2764.  
  2765. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2766.             push offset PRT_BUF
  2767.             call itoa
  2768.             inc bx                  ;Advance pointer
  2769.             inc bx
  2770.             mov di,offset PRT_BUF   ;Print alpha string
  2771.             jmp p1_alpha
  2772.  
  2773. p1_lint:    push [dword bx]         ;ltoa(*bx, PRT_BUF);
  2774.             push offset PRT_BUF
  2775.             call ltoa
  2776.             add bx,4                ;Advance pointer
  2777.             mov di,offset PRT_BUF   ;Print alpha string
  2778.             jmp p1_alpha
  2779.  
  2780. p1_hex:     mov ax,[bx]             ;AX = arg
  2781.             call p1_chex            ;Convert to hex
  2782.             inc bx                  ;Advance pointer
  2783.             inc bx
  2784.             jmp p1_loop             ;Loop back
  2785.  
  2786. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2787.             call p1_chex            ;Convert to hex
  2788.             mov ax,[bx]             ;AX = low word
  2789.             call p1_chex            ;Convert to hex
  2790.             add bx,4                ;Advance pointer
  2791.             jmp p1_loop             ;Loop back
  2792.  
  2793. p1_char:    mov al,[bx]             ;Output char
  2794.             push ax
  2795.             call dx
  2796.             inc bx                  ;Advance pointer
  2797.             jmp p1_loop             ;Loop back
  2798.  
  2799. p1_str:     mov al,[bx]             ;Get char
  2800.             inc bx                  ;Advance pointer
  2801.             test al,al              ;Check for null
  2802.             jz p1_sdone
  2803.             push ax                 ;Output char
  2804.             call dx
  2805.             jmp p1_str              ;Loop back
  2806.  
  2807. p1_sdone:   jmp p1_loop             ;Return to main loop
  2808.  
  2809. p1_alpha:   mov al,[di]             ;Get char
  2810.             test al,al              ;Check for null
  2811.             jz p1_sdone
  2812.             push ax                 ;Output char
  2813.             call dx
  2814.             inc di                  ;Advance pointer
  2815.             jmp p1_alpha            ;Loop back
  2816.  
  2817. p1_chex:    mov cx,4                ;4 hex digits
  2818.             xchg al,ah              ;Reverse the order
  2819.             ror ah,cl               ;of the hex digits
  2820.             ror al,cl               ;in AX
  2821.  
  2822. p1_hloop:   push ax                 ;Save AX
  2823.             and al,0Fh              ;Keep 4 bits
  2824.             cmp al,0Ah              ;Compute the hex digit,
  2825.             sbb al,69h              ;using Improved Allison's Algorithm
  2826.             das
  2827.             push ax                 ;Output char
  2828.             call dx
  2829.             pop ax                  ;Restore AX
  2830.             shr ax,4                ;Shift it over
  2831.             loop p1_hloop           ;Loop back
  2832.             ret                     ;Return
  2833.  
  2834. EndP        xprintf
  2835.  
  2836. End
  2837.  
  2838. ~~~C_CPULVL
  2839. Ideal
  2840.  
  2841. Public      cputype
  2842.  
  2843. Model Tiny
  2844. P386
  2845. CodeSeg
  2846.  
  2847. ;**************************** cputype() -- Returns CPU level
  2848. ;int cputype(void);
  2849.  
  2850. Proc        cputype
  2851.  
  2852.             push es            ;Save ES
  2853.             pusha              ;Save gen. regs
  2854.  
  2855.             call p1_getcpu     ;Call main procedure
  2856.  
  2857.             shr ax,8           ;AL = AH, AH = 0
  2858.             mov es,ax          ;ES = AX
  2859.             popa               ;Restore gen. regs
  2860.             mov ax,es          ;Return value in AX
  2861.             pop es             ;Restore ES
  2862.             ret                ;Return
  2863.  
  2864. p1_getcpu:  mov cx,0121h       ;If CH can be shifted by 21h,
  2865.             shl ch,cl          ;then it's an 8086, because
  2866.             jz p1_8086         ;a 186+ limits shift counts.
  2867.  
  2868.             push sp            ;If SP is pushed as its
  2869.             pop ax             ;original value, then
  2870.             cmp ax,sp          ;it's a 286+.
  2871.             jne p1_186
  2872.  
  2873.             pushf              ;Save flags
  2874.             cli                ;No interrupts
  2875.             pushf              ;AX = flags
  2876.             pop ax
  2877.             xor ax,7000h       ;Toggle IOPL bit
  2878.             push ax            ;Flags = AX
  2879.             popf
  2880.             pushf              ;BX = flags
  2881.             pop bx
  2882.             popf               ;Restore flags
  2883.             cmp ax,bx          ;If the bit was not
  2884.             jne p1_286         ;reset, it's a 386+
  2885. P386
  2886.             push bp            ;Align stack to dword
  2887.             mov bp,sp
  2888.             and sp,0FFFCh
  2889.             pushfd             ;Save eflags
  2890.             cli                ;No interrupts
  2891.             pushfd             ;EAX = eflags
  2892.             pop eax
  2893.             mov ebx,eax        ;EBX = eflags
  2894.             xor eax,40000h     ;Toggle AC bit
  2895.             push eax           ;Eflags = EAX
  2896.             popfd
  2897.             pushfd             ;EAX = eflags
  2898.             pop eax
  2899.             popfd              ;Restore eflags
  2900.             mov sp,bp          ;Restore stack
  2901.             pop bp
  2902.             cmp eax,ebx        ;If the bit was not
  2903.             je p1_386          ;reset, it's a 486+
  2904.  
  2905.             pushfd             ;Save eflags
  2906.             cli                ;No interrupts
  2907.             pushfd             ;EAX = eflags
  2908.             pop eax
  2909.             xor eax,200000h    ;Toggle ID bit
  2910.             push eax           ;Eflags = EAX
  2911.             popfd
  2912.             pushfd             ;EBX = eflags
  2913.             pop ebx
  2914.             popfd              ;Restore eflags
  2915.             cmp eax,ebx        ;If the bit was not
  2916.             jne p1_486         ;reset, it's a 586+
  2917. P586
  2918.             xor eax,eax        ;EAX = 1
  2919.             inc ax
  2920.             cpuid              ;Get CPU type
  2921.             ret                ;Return
  2922. P186
  2923. p1_486:     mov ah,4           ;486, return 4
  2924.             ret
  2925.  
  2926. p1_386:     mov ah,3           ;386, return 3
  2927.             ret
  2928.  
  2929. p1_286:     mov ah,2           ;286, return 2
  2930.             ret
  2931.  
  2932. p1_186:     mov ah,1           ;186, return 1
  2933.             ret
  2934.  
  2935. p1_8086:    mov ah,0           ;8086, return 0
  2936.             ret
  2937.  
  2938. EndP        cputype
  2939.  
  2940. End
  2941.  
  2942. ~~~C_FPULVL
  2943. Ideal
  2944.  
  2945. Public      fputype
  2946.  
  2947. Model Tiny
  2948. P386
  2949. CodeSeg
  2950.  
  2951. ;**************************** fputype() -- Returns FPU level, init FPU
  2952. ;int fputype(void);                        -1 means no FPU
  2953.  
  2954. Proc        fputype
  2955.  
  2956.             push es            ;Save ES
  2957.             pusha              ;Save gen. regs
  2958.  
  2959.             call p2_getfpu     ;Get FPU type
  2960.  
  2961.             mov es,ax          ;ES = AX
  2962.             popa               ;Restore gen. regs
  2963.             mov ax,es          ;Return value in AX
  2964.             pop es             ;Restore ES
  2965.             ret                ;Return
  2966. P8087
  2967. p2_getfpu:  fninit             ;Initialize FPU
  2968.             mov [Junk],55AAh   ;Set junk value
  2969.             fnstsw [Junk]      ;Store status word
  2970.             cmp [byte Junk],0  ;If it's not 0, no FPU
  2971.             jne p2_nofpu
  2972.             fnstcw [Junk]      ;Store control word
  2973.             mov ax,[Junk]      ;If the bits are not the way
  2974.             and ax,103Fh       ;they should be, no FPU
  2975.             cmp ax,3Fh
  2976.             jne p2_nofpu
  2977.  
  2978.             and [Junk],0FF7Fh  ;Clear interrupt bit
  2979.             fldcw [Junk]       ;Load control word
  2980.             fdisi              ;Disable interrupts
  2981.             fstcw [Junk]       ;Store control word
  2982.             test [Junk],80h    ;If it changed, it's an 8087
  2983.             jnz p2_8087
  2984. P286
  2985. P287
  2986.             finit              ;Re-initialize
  2987.             fld1               ;Divide 1 by 0 to get
  2988.             fldz               ;a positive infinity
  2989.             fdiv
  2990.             fld st             ;Get a negative infinity
  2991.             fchs
  2992.             fcompp             ;Compare them
  2993.             fstsw ax           ;Store status word
  2994.             sahf               ;If the FPU thought that they
  2995.             je p2_287          ;were equal, it's a 287
  2996.  
  2997.             mov ax,3           ;387, return 3
  2998.             finit              ;Init processor
  2999.             ret
  3000.  
  3001. p2_287:     mov ax,2           ;287, return 2
  3002.             finit              ;Init processor
  3003.             ret
  3004. P386
  3005. P8087
  3006. p2_8087:    xor ax,ax          ;8087, return 0
  3007.             finit              ;Init processor
  3008.             ret
  3009.  
  3010. p2_nofpu:   mov ax,-1          ;No FPU, return -1
  3011.             ret
  3012.  
  3013. Junk        dw 0
  3014.  
  3015. EndP        fputype
  3016.  
  3017. End
  3018.  
  3019. ~~~C_RAND
  3020. Ideal
  3021.  
  3022. Public      rand,srand,truerand
  3023.  
  3024. Model Tiny
  3025. P386
  3026. CodeSeg
  3027.  
  3028. RandNum     dd 0                    ;Random number
  3029.  
  3030. ;****************** rand() -- Returns a random number below N
  3031. ;int rand(int max);
  3032.  
  3033. max         equ bp+4
  3034.  
  3035. Proc        rand
  3036.  
  3037.             push bp                 ;Set up stack frame
  3038.             mov bp,sp
  3039.             push bx edx             ;Save registers
  3040.  
  3041.             imul edx,[RandNum],19660Dh
  3042.             add edx,10DCDh          ;EAX = RandNum * 19660Dh + 10DCDh
  3043.             mov [RandNum],edx       ;Save random number
  3044.             shr edx,15              ;AX = bits 15-30
  3045.             xchg ax,dx
  3046.             mov bx,[max]            ;BX = maximum
  3047.             xor dx,dx               ;Zero DX
  3048.             test bx,bx              ;Can't divide by zero
  3049.             jz p1_skip
  3050.             div bx                  ;Divide by BX
  3051. p1_skip:    xchg ax,dx              ;Result in AX
  3052.  
  3053.             pop edx bx              ;Restore registers
  3054.             pop bp                  ;Delete stack frame
  3055.             ret 2                   ;Return
  3056.  
  3057. EndP        rand
  3058.  
  3059. ;****************** srand() -- Seeds the RNG with the time
  3060. ;void srand(void);
  3061.  
  3062. Proc        srand
  3063.  
  3064.             push bp                 ;Set up stack frame
  3065.             mov bp,sp
  3066.             push es eax             ;Save registers
  3067.  
  3068.             push 40h                ;ES = BIOS segment
  3069.             pop es
  3070.  
  3071.             mov eax,[es:6Ch]        ;Get low word
  3072.             mov [RandNum],eax       ;Save it
  3073.  
  3074.             pop eax es              ;Restore registers
  3075.             pop bp                  ;Delete stack frame
  3076.             ret                     ;Return
  3077.  
  3078. EndP        srand
  3079.  
  3080. ;****************** truerand() -- Returns a true random number below N
  3081. ;int truerand(int max);           Extremely slow, but it works
  3082.  
  3083. max         equ bp+4
  3084.  
  3085. Proc        truerand
  3086.  
  3087.             push bp                 ;Set up stack frame
  3088.             mov bp,sp
  3089.             push bx cx dx           ;Save registers
  3090.  
  3091.             mov cx,96               ;96 iterations
  3092.             cli                     ;No interrupts allowed
  3093.  
  3094. p1_loop:    mov al,06h              ;Set timer command
  3095.             out 43h,al
  3096.             jmp $+2
  3097.             in al,40h               ;Read LSB of timer
  3098.             xor dl,al               ;XOR into DX
  3099.             jmp $+2
  3100.             in al,40h               ;Read MSB of timer
  3101.             xor dl,al               ;XOR into DX
  3102.             rol dx,3                ;Rotate left
  3103.             loop p1_loop            ;Loop back
  3104.  
  3105.             sti                     ;Enable interrupts
  3106.             xchg ax,dx              ;Result in AX
  3107.  
  3108.             mov bx,[max]            ;BX = maximum
  3109.             xor dx,dx               ;Zero DX
  3110.             test bx,bx              ;Can't divide by zero
  3111.             jz p3_skip
  3112.             div bx                  ;Divide by BX
  3113. p3_skip:    xchg ax,dx              ;Result in AX
  3114.  
  3115.             pop dx cx bx            ;Restore registers
  3116.             pop bp                  ;Delete stack frame
  3117.             ret 2                   ;Return
  3118.  
  3119. EndP        truerand
  3120.  
  3121. End
  3122.  
  3123. ~~~C_DELAY
  3124. Ideal
  3125.  
  3126. Public      delay
  3127.  
  3128. Model Tiny
  3129. P386
  3130. CodeSeg
  3131.  
  3132. ;****************** delay() -- Delay in milliseconds
  3133. ;void delay(int dtime);
  3134.  
  3135. dtime       equ bp+4
  3136.  
  3137. Proc        delay
  3138.  
  3139.             push bp                 ;Set up stack frame
  3140.             mov bp,sp
  3141.             pusha                   ;Save registers
  3142.  
  3143.             mov ax,[dtime]          ;AX = time in milliseconds
  3144.             mov dx,1000             ;Multiply by 1000
  3145.             mul dx                  ;DX:AX = time in microseconds
  3146.  
  3147.             mov cx,dx               ;CX:DX = time
  3148.             xchg dx,ax
  3149.             mov ah,86h              ;BIOS Delay Service
  3150.             int 15h
  3151.  
  3152.             popa                    ;Restore registers
  3153.             pop bp                  ;Delete stack frame
  3154.             ret 2                   ;Return
  3155.  
  3156. EndP        delay
  3157.  
  3158. End
  3159.  
  3160. ~~~C_SOUND
  3161. Ideal
  3162.  
  3163. Public      sound,nosound
  3164.  
  3165. Model Tiny
  3166. P386
  3167. CodeSeg
  3168.  
  3169. ;****************** sound() -- Turn on speaker at specific frequency
  3170. ;void sound(int freq);
  3171.  
  3172. freq        equ bp+4
  3173.  
  3174. Proc        sound
  3175.  
  3176.             push bp                 ;Set up stack frame
  3177.             mov bp,sp
  3178.             pusha                   ;Save registers
  3179.  
  3180.             mov dx,12h              ;BX = 1193180 / freq.
  3181.             mov ax,34DCh
  3182.             mov bx,[freq]
  3183.             div bx
  3184.             xchg bx,ax
  3185.  
  3186.             mov al,0B6h             ;Set frequency
  3187.             out 43h,al
  3188.             mov al,bl
  3189.             out 42h,al
  3190.             mov al,bh
  3191.             out 42h,al
  3192.  
  3193.             in al,61h               ;Turn on speaker
  3194.             or al,3
  3195.             out 61h,al
  3196.  
  3197.             popa                    ;Restore registers
  3198.             pop bp                  ;Delete stack frame
  3199.             ret 2                   ;Return
  3200.  
  3201. EndP        sound
  3202.  
  3203. ;****************** nosound() -- Turn off speaker
  3204. ;void nosound(void);
  3205.  
  3206. Proc        nosound
  3207.  
  3208.             push bp                 ;Set up stack frame
  3209.             mov bp,sp
  3210.             push ax                 ;Save AX
  3211.  
  3212.             in al,61h               ;Turn off speaker
  3213.             and al,0FCh
  3214.             out 61h,al
  3215.  
  3216.             pop ax                  ;Restore AX
  3217.             ret                     ;Return
  3218.  
  3219. EndP        nosound
  3220.  
  3221. End
  3222.